openapi: 3.1.0
info:
  title: LendEasy Servicing Client API
  version: 1.0.0
  summary: Ordinary authenticated servicing client operations implemented by the composed runtime.
  description: The implementation-backed ordinary servicing client contract. It excludes connector callbacks, internal
    AI-session/operator services, and retained future-facing product APIs.
  contact:
    name: LendEasy Developer Experience
    url: https://docs.lendeasy.ai
  x-operation-count: 221
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: 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: Privacy requests
    x-surface: servicing
    description: Access, deletion, correction, and portability workflows.
  - name: Workforce
    x-surface: servicing
    description: Composed human users, AI worker registrations, eligibility, and presence.
  - name: Supercases
    x-surface: servicing
    description: Bounded portfolio-event containers and structurally linked customer subcases.
  - name: Case notes
    x-surface: servicing
    description: Revisioned, link-aware, sensitive operational notes owned by the servicing plane.
  - name: Governed operations
    x-surface: servicing
    description: Case-scoped operations that execute directly when allowed and create a request only when policy requires one.
  - name: Case effects
    x-surface: servicing
    description: Workflow-created typed effects, status reads, and terminal-failure recovery.
  - name: AI governance
    x-surface: servicing
    description: Reviewable AI outputs and scope-specific suppression controls.
  - name: Servicing administration
    x-surface: servicing
    description: Case-type, reason, review-timer, allocation, queue-coverage, and field configuration owned by the servicing plane.
  - name: Workflow administration
    x-surface: servicing
    description: Workflow-definition drafting, validation, vocabulary, import/export, and versioned activation under a
      separate promotion authority.
  - name: Voice
    x-surface: servicing
    description: Outbound AI voice dispatch, execution-time dial authorization, dial grants, and the voice-provider console
      pass-through.
  - name: Servicing reports
    x-surface: servicing
    description: Bounded workforce, collections, interaction, compliance, AI-quality, reconciliation, and promise-allocation
      projections, plus the curated investor reporting pack and the drift workspace.
  - name: Evidence exports
    x-surface: servicing
    description: Audited case and customer evidence bundles reconstructed from retained causal records.
  - name: Scheduled callbacks
    x-surface: servicing
    description: Borrower-promised callback windows held as first-class tasks with window-scoped consent and at-dial compliance.
  - name: Email threads
    x-surface: servicing
    description: Email conversation threads with bounded previews, audited body reads, and governed threaded replies.
  - name: Cookie
    x-surface: servicing
    description: "The case copilot: panel context, threads, turns, feedback, proposal confirmation, and its admin surface."
  - name: Hardship
    x-surface: servicing
    description: Versioned hardship policies and guardrails, case hardship state and offers, and evidence-analysis review.
  - name: Portal contracts
    x-surface: servicing
    description: "The servicing side of borrower self-service: agreements, documents, invitations, interactions, message
      tasks, signals, and upload sessions."
security:
  - oauth2: []
paths:
  /v1/servicing/cases:
    post:
      tags:
        - Cases
      operationId: createCase
      summary: Create or deduplicate a case
      description: Creates a durable matter, instantiates its pinned workflow, routes initial work, and returns an exact
        source/open-case match instead of creating a duplicate.
      x-permission: CREATE_SERVICING_CASE
      x-idempotent: true
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: Idempotency-Key
          in: header
          required: false
          description: Optional replay key for this logical mutation. Omission creates a fresh server-owned key for this attempt;
            blank, repeated, or longer-than-50-character values are rejected.
          schema:
            type: string
            minLength: 1
            maxLength: 50
      responses:
        "201":
          description: Created.
          content:
            application/json:
              schema:
                type: object
                required:
                  - caseId
                  - externalCaseRef
                  - status
                  - deduplicated
                  - resourceId
                properties:
                  caseId:
                    type: integer
                    description: Stable opaque servicing case identifier.
                  externalCaseRef:
                    type: string
                  status:
                    type: string
                    description: Current normalized lifecycle state.
                  deduplicated:
                    type: boolean
                  resourceId:
                    type: integer
              example:
                caseId: 1001
                externalCaseRef: LE-CASE-1001
                status: OPEN
                deduplicated: false
                resourceId: 1001
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
        "409":
          $ref: "#/components/responses/Servicing409Error"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - customerRef
                - caseTypeCode
                - reasonCode
                - priority
              properties:
                customerRef:
                  type: string
                caseTypeCode:
                  type: string
                reasonCode:
                  type: string
                  description: Configured structured reason code.
                priority:
                  type: string
                loanRefs:
                  type: array
                  items:
                    type: string
                ownerQueueCode:
                  type: string
                sourceType:
                  type: string
                sourceRef:
                  type: string
                summary:
                  type: string
                fields:
                  type: object
                  required:
                    - delinquency_bucket
                  properties:
                    delinquency_bucket:
                      type: string
              example:
                customerRef: "123"
                caseTypeCode: COLLECTIONS
                reasonCode: DELINQUENCY_SIGNAL
                priority: HIGH
                loanRefs:
                  - "456"
                ownerQueueCode: COLLECTIONS
                sourceType: LMS_EVENT
                sourceRef: event-789
                summary: Customer entered delinquency bucket 1-15.
                fields:
                  delinquency_bucket: DAYS_1_15
            example:
              customerRef: "123"
              caseTypeCode: COLLECTIONS
              reasonCode: DELINQUENCY_SIGNAL
              priority: HIGH
              loanRefs:
                - "456"
              ownerQueueCode: COLLECTIONS
              sourceType: LMS_EVENT
              sourceRef: event-789
              summary: Customer entered delinquency bucket 1-15.
              fields:
                delinquency_bucket: DAYS_1_15
    get:
      tags:
        - Cases
      operationId: listCases
      summary: List cases
      description: Returns permission-filtered case summaries using exact structured filters and stable offset pagination.
        Keyword and global-search parameters are rejected.
      x-permission: READ_SERVICING_CASE
      x-idempotent: false
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: externalCaseRef
          in: query
          required: false
          description: Exact canonical external case reference.
          schema:
            type: string
        - name: customerRef
          in: query
          required: false
          description: Exact customer reference.
          schema:
            type: string
        - name: loanRef
          in: query
          required: false
          description: Exact linked loan reference.
          schema:
            type: string
        - name: supercaseId
          in: query
          required: false
          description: Exact structurally linked supercase ID.
          schema:
            type: integer
        - name: caseTypeCode
          in: query
          required: false
          description: Exact configured case-type code.
          schema:
            type: string
        - name: status
          in: query
          required: false
          description: Repeat to include multiple case states.
          schema:
            type: string
        - name: priority
          in: query
          required: false
          description: Repeat to include multiple priorities.
          schema:
            type: string
            enum:
              - LOW
              - NORMAL
              - HIGH
              - CRITICAL
        - name: owner
          in: query
          required: false
          description: Worker ID, me, or unassigned.
          schema:
            type: string
        - name: queueCode
          in: query
          required: false
          description: Exact owner queue code.
          schema:
            type: string
        - name: sensitive
          in: query
          required: false
          description: Filter by sensitivity.
          schema:
            type: boolean
        - name: openedFrom
          in: query
          required: false
          description: Inclusive timestamp lower bound.
          schema:
            type: string
            format: date-time
        - name: openedTo
          in: query
          required: false
          description: Exclusive timestamp upper bound.
          schema:
            type: string
            format: date-time
        - name: limit
          in: query
          required: false
          description: Maximum rows to return; defaults to 50.
          schema:
            type: integer
            minimum: 1
            maximum: 200
            default: 50
        - name: offset
          in: query
          required: false
          description: Zero-based row offset; defaults to 0.
          schema:
            type: integer
            minimum: 0
            default: 0
        - name: sort
          in: query
          required: false
          description: Allowlisted sort field for this collection.
          schema:
            type: string
        - name: order
          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:
                  - items
                  - limit
                  - offset
                  - hasMore
                properties:
                  items:
                    type: array
                    items:
                      type: object
                      required:
                        - caseId
                        - externalCaseRef
                        - customerRef
                        - caseTypeCode
                        - reasonCode
                        - status
                        - priority
                        - ownerQueueCode
                        - serviceLevelDueAt
                        - lastUpdatedAt
                        - sensitive
                      properties:
                        caseId:
                          type: integer
                          description: Stable opaque servicing case identifier.
                        externalCaseRef:
                          type: string
                        customerRef:
                          type: string
                        caseTypeCode:
                          type: string
                        reasonCode:
                          type: string
                          description: Configured structured reason code.
                        status:
                          type: string
                          description: Current normalized lifecycle state.
                        priority:
                          type: string
                        ownerQueueCode:
                          type: string
                        serviceLevelDueAt:
                          type: string
                          format: date-time
                        lastUpdatedAt:
                          type: string
                          format: date-time
                        sensitive:
                          type: boolean
                  limit:
                    type: integer
                  offset:
                    type: integer
                  hasMore:
                    type: boolean
              example:
                items:
                  - caseId: 1001
                    externalCaseRef: LE-CASE-1001
                    customerRef: "123"
                    caseTypeCode: COLLECTIONS
                    reasonCode: DELINQUENCY_SIGNAL
                    status: OPEN
                    priority: HIGH
                    ownerQueueCode: COLLECTIONS
                    serviceLevelDueAt: 2026-07-26T17:00:00Z
                    lastUpdatedAt: 2026-07-25T18:30:00Z
                    sensitive: false
                limit: 50
                offset: 0
                hasMore: false
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
  /v1/servicing/cases/{caseId}:
    get:
      tags:
        - Cases
      operationId: getCase
      summary: Retrieve a case workspace
      description: Returns the case header, owner and opener identity, the narrated workflow journey with per-stage timestamps
        and tasks, the work summary, configured fields, relationships, linked work and content summaries, warnings,
        allowed transitions, and any open escalation. Stage and journey timestamps are ISO 8601 UTC.
      x-permission: READ_SERVICING_CASE
      x-idempotent: false
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: caseId
          in: path
          required: true
          description: Positive numeric case identifier.
          schema:
            type: integer
            format: int64
            minimum: 1
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - caseId
                  - externalCaseRef
                  - customerRef
                  - caseTypeCode
                  - reasonCode
                  - status
                  - priority
                  - ownerQueueCode
                  - serviceLevelDueAt
                  - lastUpdatedAt
                  - sensitive
                  - ownerDisplayName
                  - ownerWorkerKind
                  - openedByActorType
                  - openedByDisplayName
                  - workflow
                  - workSummary
                  - availableTransitions
                  - fields
                  - fieldDefinitions
                  - linkedLoanRefs
                  - openTasks
                  - relationships
                  - actionRequests
                  - complianceWarnings
                properties:
                  caseId:
                    type: integer
                    description: Stable opaque servicing case identifier.
                  externalCaseRef:
                    type: string
                  customerRef:
                    type: string
                  caseTypeCode:
                    type: string
                  reasonCode:
                    type: string
                    description: Configured structured reason code.
                  status:
                    type: string
                    description: Current normalized lifecycle state.
                  priority:
                    type: string
                  ownerQueueCode:
                    type: string
                  serviceLevelDueAt:
                    type: string
                    format: date-time
                  lastUpdatedAt:
                    type: string
                    format: date-time
                  sensitive:
                    type: boolean
                  ownerDisplayName:
                    type: string
                  ownerWorkerKind:
                    type: string
                  openedByActorType:
                    type: string
                  openedByDisplayName:
                    type: string
                  workflow:
                    type: object
                    required:
                      - workflowKey
                      - version
                      - status
                      - currentStageCode
                      - currentStageDisplayName
                      - stages
                    properties:
                      workflowKey:
                        type: string
                      version:
                        type: integer
                        description: Monotonically increasing resource version.
                      status:
                        type: string
                        description: Current normalized lifecycle state.
                      currentStageCode:
                        type: string
                      currentStageDisplayName:
                        type: string
                      stages:
                        type: array
                        items:
                          type: object
                          required:
                            - stageKey
                            - displayName
                            - description
                            - state
                            - enteredAt
                            - exitedAt
                            - tasks
                          properties:
                            stageKey:
                              type: string
                            displayName:
                              type: string
                            description:
                              type: string
                            state:
                              type: string
                            enteredAt:
                              type: string
                              format: date-time
                            exitedAt:
                              type: string
                              format: date-time
                            tasks:
                              type: array
                              items:
                                type: object
                                required:
                                  - taskId
                                  - taskTypeCode
                                  - summary
                                  - status
                                  - outcomeCode
                                properties:
                                  taskId:
                                    type: integer
                                  taskTypeCode:
                                    type: string
                                  summary:
                                    type: string
                                  status:
                                    type: string
                                    description: Current normalized lifecycle state.
                                  outcomeCode:
                                    type: string
                  workSummary:
                    type: object
                    required:
                      - taskCounts
                      - openTaskCount
                      - nextAction
                    properties:
                      taskCounts:
                        type: object
                        required:
                          - COMPLETED
                          - ACCEPTED
                        properties:
                          COMPLETED:
                            type: integer
                          ACCEPTED:
                            type: integer
                      openTaskCount:
                        type: integer
                      nextAction:
                        type: object
                        required:
                          - taskId
                          - taskTypeCode
                          - queueCode
                          - status
                          - priority
                          - dueAt
                        properties:
                          taskId:
                            type: integer
                          taskTypeCode:
                            type: string
                          queueCode:
                            type: string
                          status:
                            type: string
                            description: Current normalized lifecycle state.
                          priority:
                            type: string
                          dueAt:
                            type: string
                            format: date-time
                  availableTransitions:
                    type: array
                    items:
                      type: string
                  fields:
                    type: object
                    required:
                      - delinquency_bucket
                    properties:
                      delinquency_bucket:
                        type: string
                  fieldDefinitions:
                    type: object
                    required:
                      - sections
                    properties:
                      sections:
                        type: array
                        items:
                          type: object
                  linkedLoanRefs:
                    type: array
                    items:
                      type: string
                  openTasks:
                    type: array
                    items:
                      type: object
                      required:
                        - taskId
                        - caseId
                        - taskTypeCode
                        - status
                        - priority
                        - queueCode
                        - dueAt
                        - sensitive
                      properties:
                        taskId:
                          type: integer
                        caseId:
                          type: integer
                          description: Stable opaque servicing case identifier.
                        taskTypeCode:
                          type: string
                        status:
                          type: string
                          description: Current normalized lifecycle state.
                        priority:
                          type: string
                        queueCode:
                          type: string
                        dueAt:
                          type: string
                          format: date-time
                        sensitive:
                          type: boolean
                  relationships:
                    type: array
                    items:
                      type: object
                  actionRequests:
                    type: array
                    items:
                      type: object
                  complianceWarnings:
                    type: array
                    items:
                      type: object
              example:
                caseId: 1001
                externalCaseRef: LE-CASE-1001
                customerRef: "123"
                caseTypeCode: COLLECTIONS
                reasonCode: DELINQUENCY_SIGNAL
                status: OPEN
                priority: HIGH
                ownerQueueCode: COLLECTIONS
                serviceLevelDueAt: 2026-07-26T17:00:00Z
                lastUpdatedAt: 2026-07-25T18:30:00Z
                sensitive: false
                ownerDisplayName: Maria Agent
                ownerWorkerKind: HUMAN
                openedByActorType: SYSTEM
                openedByDisplayName: LMS signal ingestion
                workflow:
                  workflowKey: COLLECTIONS_STANDARD
                  version: 2
                  status: ACTIVE
                  currentStageCode: MONITOR_PROMISE
                  currentStageDisplayName: Monitor the promise
                  stages:
                    - stageKey: INTAKE
                      displayName: Intake and route
                      description: Confirm the case belongs here and route it to the queue that can act on it.
                      state: COMPLETED
                      enteredAt: 2026-07-24T16:11:02Z
                      exitedAt: 2026-07-24T18:03:47Z
                      tasks:
                        - taskId: 2001
                          taskTypeCode: COLLECTIONS_OUTREACH
                          summary: Review the delinquency signal.
                          status: COMPLETED
                          outcomeCode: CUSTOMER_REACHED
                    - stageKey: MONITOR_PROMISE
                      displayName: Monitor the promise
                      state: CURRENT
                      enteredAt: 2026-07-25T18:30:00Z
                      tasks: []
                workSummary:
                  taskCounts:
                    COMPLETED: 1
                    ACCEPTED: 1
                  openTaskCount: 1
                  nextAction:
                    taskId: 2002
                    taskTypeCode: COLLECTIONS_OUTREACH
                    queueCode: COLLECTIONS
                    status: ACCEPTED
                    priority: HIGH
                    dueAt: 2026-07-26T17:00:00Z
                availableTransitions:
                  - SNOOZED
                  - WAITING_ON_BORROWER
                fields:
                  delinquency_bucket: DAYS_1_15
                fieldDefinitions:
                  sections: []
                linkedLoanRefs:
                  - "456"
                openTasks:
                  - taskId: 2001
                    caseId: 1001
                    taskTypeCode: COLLECTIONS_OUTREACH
                    status: AVAILABLE
                    priority: HIGH
                    queueCode: COLLECTIONS
                    dueAt: 2026-07-26T17:00:00Z
                    sensitive: false
                relationships: []
                actionRequests: []
                complianceWarnings: []
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
    put:
      tags:
        - Cases
      operationId: replaceCaseDetails
      summary: Update case details
      description: Updates routing-safe properties and configured field values. Workflow state changes use the transition,
        close, or reopen commands.
      x-permission: UPDATE_SERVICING_CASE
      x-idempotent: true
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: caseId
          in: path
          required: true
          description: Positive numeric case identifier.
          schema:
            type: integer
            format: int64
            minimum: 1
        - name: Idempotency-Key
          in: header
          required: false
          description: Optional replay key for this logical mutation. Omission creates a fresh server-owned key for this attempt;
            blank, repeated, or longer-than-50-character values are rejected.
          schema:
            type: string
            minLength: 1
            maxLength: 50
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - caseId
                  - resourceId
                  - changes
                properties:
                  caseId:
                    type: integer
                    description: Stable opaque servicing case identifier.
                  resourceId:
                    type: integer
                  changes:
                    type: object
                    required:
                      - priority
                      - fieldKeys
                    properties:
                      priority:
                        type: string
                      fieldKeys:
                        type: array
                        items:
                          type: string
              example:
                caseId: 1001
                resourceId: 1001
                changes:
                  priority: HIGH
                  fieldKeys:
                    - contact_outcome
                    - follow_up_date
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
        "409":
          $ref: "#/components/responses/Servicing409Error"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - reason
              properties:
                priority:
                  type: string
                summary:
                  type: string
                fields:
                  type: object
                  required:
                    - contact_outcome
                    - follow_up_date
                  properties:
                    contact_outcome:
                      type: string
                    follow_up_date:
                      type: string
                      format: date
                reason:
                  type: string
              example:
                priority: HIGH
                summary: Customer supplied the requested servicing details.
                fields:
                  contact_outcome: CUSTOMER_REACHED
                  follow_up_date: 2026-07-27
                reason: Recorded the result of the customer call.
            example:
              priority: HIGH
              summary: Customer supplied the requested servicing details.
              fields:
                contact_outcome: CUSTOMER_REACHED
                follow_up_date: 2026-07-27
              reason: Recorded the result of the customer call.
  /v1/servicing/cases/{caseId}/transitions:
    post:
      tags:
        - Cases
      operationId: transitionCase
      summary: Transition a case
      description: Applies one transition allowed by the case state machine and pinned workflow. Close and reopen use
        separately authorized routes.
      x-permission: UPDATE_SERVICING_CASE
      x-idempotent: true
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: caseId
          in: path
          required: true
          description: Positive numeric case identifier.
          schema:
            type: integer
            format: int64
            minimum: 1
        - name: Idempotency-Key
          in: header
          required: false
          description: Optional replay key for this logical mutation. Omission creates a fresh server-owned key for this attempt;
            blank, repeated, or longer-than-50-character values are rejected.
          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:
                      - status
                      - resumeDate
                    properties:
                      status:
                        type: string
                        description: Current normalized lifecycle state.
                      resumeDate:
                        type: string
                        format: date
              example:
                resourceId: 1001
                changes:
                  status: SNOOZED
                  resumeDate: 2026-08-01
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
        "409":
          $ref: "#/components/responses/Servicing409Error"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - targetStatus
                - reason
              properties:
                targetStatus:
                  type: string
                reason:
                  type: string
                resumeDate:
                  type: string
                  format: date
              example:
                targetStatus: SNOOZED
                reason: Customer promised to pay on the agreed date.
                resumeDate: 2026-08-01
            example:
              targetStatus: SNOOZED
              reason: Customer promised to pay on the agreed date.
              resumeDate: 2026-08-01
  /v1/servicing/cases/{caseId}/close:
    post:
      tags:
        - Cases
      operationId: closeCase
      summary: Close a case
      description: Closes a case only after required fields, tasks, requests, effects, and workflow closure criteria are satisfied.
      x-permission: CLOSE_SERVICING_CASE
      x-idempotent: true
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: caseId
          in: path
          required: true
          description: Positive numeric case identifier.
          schema:
            type: integer
            format: int64
            minimum: 1
        - name: Idempotency-Key
          in: header
          required: false
          description: Optional replay key for this logical mutation. Omission creates a fresh server-owned key for this attempt;
            blank, repeated, or longer-than-50-character values are rejected.
          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:
                      - status
                      - outcomeCode
                    properties:
                      status:
                        type: string
                        description: Current normalized lifecycle state.
                      outcomeCode:
                        type: string
              example:
                resourceId: 1001
                changes:
                  status: CLOSED
                  outcomeCode: PROMISE_KEPT
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
        "409":
          $ref: "#/components/responses/Servicing409Error"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - outcomeCode
                - closureReason
              properties:
                outcomeCode:
                  type: string
                closureReason:
                  type: string
              example:
                outcomeCode: PROMISE_KEPT
                closureReason: Customer cured delinquency and no follow-up remains.
            example:
              outcomeCode: PROMISE_KEPT
              closureReason: Customer cured delinquency and no follow-up remains.
  /v1/servicing/cases/{caseId}/escalate:
    post:
      tags:
        - Cases
      operationId: escalateCase
      summary: Escalate a case
      description: "Escalates a case to a PERSON, QUEUE, SUPERVISOR, or COMPLIANCE_REVIEWER with NORMAL, URGENT, or IMMEDIATE
        urgency and a future response deadline, creating the escalation record and its work. COMPLIANCE_REVIEWER
        additionally requires a permitted complianceReviewReason: POTENTIAL_CONSUMER_HARM, CONTROL_FAILURE, or
        COMPLAINT_OR_REGULATORY_INQUIRY."
      x-permission: ESCALATE_SERVICING_CASE
      x-idempotent: true
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: caseId
          in: path
          required: true
          description: Positive numeric case identifier.
          schema:
            type: integer
            format: int64
            minimum: 1
        - name: Idempotency-Key
          in: header
          required: false
          description: Optional replay key for this logical mutation. Omission creates a fresh server-owned key for this attempt;
            blank, repeated, or longer-than-50-character values are rejected.
          schema:
            type: string
            minLength: 1
            maxLength: 50
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - caseId
                  - resourceId
                  - changes
                properties:
                  caseId:
                    type: integer
                    description: Stable opaque servicing case identifier.
                  resourceId:
                    type: integer
                  changes:
                    type: object
                    required:
                      - status
                      - escalationId
                      - externalEscalationRef
                      - taskId
                    properties:
                      status:
                        type: string
                        description: Current normalized lifecycle state.
                      escalationId:
                        type: integer
                      externalEscalationRef:
                        type: string
                      taskId:
                        type: integer
              example:
                caseId: 1001
                resourceId: 1001
                changes:
                  status: ESCALATED
                  escalationId: 9001
                  externalEscalationRef: LE-ESC-9001
                  taskId: 2003
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
        "409":
          $ref: "#/components/responses/Servicing409Error"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - targetType
                - targetRef
                - reason
                - urgency
                - responseDeadline
              properties:
                targetType:
                  type: string
                targetRef:
                  type: string
                reason:
                  type: string
                urgency:
                  type: string
                responseDeadline:
                  type: string
              example:
                targetType: SUPERVISOR
                targetRef: "4103"
                reason: Customer dispute needs supervisor review before further outreach.
                urgency: URGENT
                responseDeadline: 2026-07-26T17:00:00Z
            example:
              targetType: SUPERVISOR
              targetRef: "4103"
              reason: Customer dispute needs supervisor review before further outreach.
              urgency: URGENT
              responseDeadline: 2026-07-26T17:00:00Z
  /v1/servicing/tasks:
    get:
      tags:
        - Tasks
      operationId: listTasks
      summary: List tasks
      description: Lists visible work using exact queue, state, case, assignment, due, sensitivity, and priority filters.
      x-permission: READ_SERVICING_TASK
      x-idempotent: false
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: queueCode
          in: query
          required: false
          description: Exact queue code.
          schema:
            type: string
        - name: status
          in: query
          required: false
          description: Repeat to include multiple task states.
          schema:
            type: string
        - name: caseTypeCode
          in: query
          required: false
          description: Exact owning case type.
          schema:
            type: string
        - name: priority
          in: query
          required: false
          description: Repeat to include multiple priorities.
          schema:
            type: string
        - name: assignedTo
          in: query
          required: false
          description: Worker ID, me, or unassigned.
          schema:
            type: string
        - name: overdue
          in: query
          required: false
          description: Filter overdue work.
          schema:
            type: boolean
        - name: sensitive
          in: query
          required: false
          description: Filter by sensitivity.
          schema:
            type: boolean
        - name: caseId
          in: query
          required: false
          description: Exact owning case ID.
          schema:
            type: integer
        - name: dueFrom
          in: query
          required: false
          description: Inclusive timestamp lower bound.
          schema:
            type: string
            format: date-time
        - name: dueTo
          in: query
          required: false
          description: Exclusive timestamp upper bound.
          schema:
            type: string
            format: date-time
        - name: limit
          in: query
          required: false
          description: Maximum rows to return; defaults to 50.
          schema:
            type: integer
            minimum: 1
            maximum: 200
            default: 50
        - name: offset
          in: query
          required: false
          description: Zero-based row offset; defaults to 0.
          schema:
            type: integer
            minimum: 0
            default: 0
        - name: sort
          in: query
          required: false
          description: Allowlisted sort field for this collection.
          schema:
            type: string
        - name: order
          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:
                  - items
                  - limit
                  - offset
                  - hasMore
                properties:
                  items:
                    type: array
                    items:
                      type: object
                      required:
                        - taskId
                        - caseId
                        - taskTypeCode
                        - status
                        - priority
                        - queueCode
                        - dueAt
                        - sensitive
                      properties:
                        taskId:
                          type: integer
                        caseId:
                          type: integer
                          description: Stable opaque servicing case identifier.
                        taskTypeCode:
                          type: string
                        status:
                          type: string
                          description: Current normalized lifecycle state.
                        priority:
                          type: string
                        queueCode:
                          type: string
                        dueAt:
                          type: string
                          format: date-time
                        sensitive:
                          type: boolean
                  limit:
                    type: integer
                  offset:
                    type: integer
                  hasMore:
                    type: boolean
              example:
                items:
                  - taskId: 2001
                    caseId: 1001
                    taskTypeCode: COLLECTIONS_OUTREACH
                    status: AVAILABLE
                    priority: HIGH
                    queueCode: COLLECTIONS
                    dueAt: 2026-07-26T17:00:00Z
                    sensitive: false
                limit: 50
                offset: 0
                hasMore: false
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
  /v1/servicing/tasks/{taskId}/accept:
    post:
      tags:
        - Tasks
      operationId: acceptTask
      summary: Accept a reserved task
      description: Accepts the authenticated worker’s live reservation. The command accepts no request body.
      x-permission: ACCEPT_SERVICING_TASK
      x-idempotent: true
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: taskId
          in: path
          required: true
          description: Positive numeric task identifier.
          schema:
            type: integer
            format: int64
            minimum: 1
        - name: Idempotency-Key
          in: header
          required: false
          description: Optional replay key for this logical mutation. Omission creates a fresh server-owned key for this attempt;
            blank, repeated, or longer-than-50-character values are rejected.
          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:
                      - status
                    properties:
                      status:
                        type: string
                        description: Current normalized lifecycle state.
              example:
                resourceId: 2001
                changes:
                  status: ACCEPTED
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
        "409":
          $ref: "#/components/responses/Servicing409Error"
  /v1/servicing/tasks/{taskId}/complete:
    post:
      tags:
        - Tasks
      operationId: completeTask
      summary: Complete a task
      description: Completes work with a valid outcome, required evidence, configured completion fields, and optional
        policy-allowed follow-up.
      x-permission: COMPLETE_SERVICING_TASK
      x-idempotent: true
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: taskId
          in: path
          required: true
          description: Positive numeric task identifier.
          schema:
            type: integer
            format: int64
            minimum: 1
        - name: Idempotency-Key
          in: header
          required: false
          description: Optional replay key for this logical mutation. Omission creates a fresh server-owned key for this attempt;
            blank, repeated, or longer-than-50-character values are rejected.
          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:
                      - status
                      - outcomeCode
                    properties:
                      status:
                        type: string
                        description: Current normalized lifecycle state.
                      outcomeCode:
                        type: string
              example:
                resourceId: 2001
                changes:
                  status: COMPLETED
                  outcomeCode: CUSTOMER_REACHED
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
        "409":
          $ref: "#/components/responses/Servicing409Error"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - outcomeCode
              properties:
                outcomeCode:
                  type: string
                note:
                  type: string
                fields:
                  type: object
                  required:
                    - identity_verified
                    - contact_channel
                  properties:
                    identity_verified:
                      type: boolean
                    contact_channel:
                      type: string
                followUp:
                  type: object
                  required:
                    - taskTypeCode
                    - dueDate
                  properties:
                    taskTypeCode:
                      type: string
                    dueDate:
                      type: string
                      format: date
              example:
                outcomeCode: CUSTOMER_REACHED
                note: Customer agreed to a promise to pay.
                fields:
                  identity_verified: true
                  contact_channel: PHONE
                followUp:
                  taskTypeCode: REVIEW_PROMISE_OUTCOME
                  dueDate: 2026-08-02
            example:
              outcomeCode: CUSTOMER_REACHED
              note: Customer agreed to a promise to pay.
              fields:
                identity_verified: true
                contact_channel: PHONE
              followUp:
                taskTypeCode: REVIEW_PROMISE_OUTCOME
                dueDate: 2026-08-02
  /v1/servicing/tasks/{taskId}/release:
    post:
      tags:
        - Tasks
      operationId: releaseTask
      summary: Release a task
      description: Releases work held by the caller and records the unable/requeue decision required by task policy.
      x-permission: ACCEPT_SERVICING_TASK
      x-idempotent: true
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: taskId
          in: path
          required: true
          description: Positive numeric task identifier.
          schema:
            type: integer
            format: int64
            minimum: 1
        - name: Idempotency-Key
          in: header
          required: false
          description: Optional replay key for this logical mutation. Omission creates a fresh server-owned key for this attempt;
            blank, repeated, or longer-than-50-character values are rejected.
          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:
                      - status
                    properties:
                      status:
                        type: string
                        description: Current normalized lifecycle state.
              example:
                resourceId: 2001
                changes:
                  status: AVAILABLE
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
        "409":
          $ref: "#/components/responses/Servicing409Error"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - unableReason
                - note
                - requeueDecision
                - createReplacementTask
                - managerReviewRequired
              properties:
                unableReason:
                  type: string
                note:
                  type: string
                requeueDecision:
                  type: string
                createReplacementTask:
                  type: boolean
                managerReviewRequired:
                  type: boolean
              example:
                unableReason: SHIFT_ENDED
                note: Returning unstarted work to the queue.
                requeueDecision: RETURN_TO_QUEUE
                createReplacementTask: false
                managerReviewRequired: false
            example:
              unableReason: SHIFT_ENDED
              note: Returning unstarted work to the queue.
              requeueDecision: RETURN_TO_QUEUE
              createReplacementTask: false
              managerReviewRequired: false
  /v1/servicing/tasks/{taskId}/cancel:
    post:
      tags:
        - Tasks
      operationId: cancelTask
      summary: Cancel a task
      description: Cancels work with a recorded reason; required workflow work blocks progression or creates replacement work.
      x-permission: CANCEL_SERVICING_TASK
      x-idempotent: true
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: taskId
          in: path
          required: true
          description: Positive numeric task identifier.
          schema:
            type: integer
            format: int64
            minimum: 1
        - name: Idempotency-Key
          in: header
          required: false
          description: Optional replay key for this logical mutation. Omission creates a fresh server-owned key for this attempt;
            blank, repeated, or longer-than-50-character values are rejected.
          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:
                      - status
                    properties:
                      status:
                        type: string
                        description: Current normalized lifecycle state.
              example:
                resourceId: 2001
                changes:
                  status: CANCELLED
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
        "409":
          $ref: "#/components/responses/Servicing409Error"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - reason
              properties:
                reason:
                  type: string
              example:
                reason: The owning case was resolved.
            example:
              reason: The owning case was resolved.
  /v1/servicing/tasks/{taskId}/reassign:
    post:
      tags:
        - Tasks
      operationId: reassignTask
      summary: Reassign a task
      description: Moves work to an eligible worker or queue after manager authorization and routing validation.
      x-permission: REASSIGN_SERVICING_TASK
      x-idempotent: true
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: taskId
          in: path
          required: true
          description: Positive numeric task identifier.
          schema:
            type: integer
            format: int64
            minimum: 1
        - name: Idempotency-Key
          in: header
          required: false
          description: Optional replay key for this logical mutation. Omission creates a fresh server-owned key for this attempt;
            blank, repeated, or longer-than-50-character values are rejected.
          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:
                      - queueCode
                      - status
                    properties:
                      queueCode:
                        type: string
                      status:
                        type: string
                        description: Current normalized lifecycle state.
              example:
                resourceId: 2001
                changes:
                  queueCode: HARDSHIP
                  status: AVAILABLE
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
        "409":
          $ref: "#/components/responses/Servicing409Error"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - targetType
                - targetRef
                - reason
              properties:
                targetType:
                  type: string
                targetRef:
                  type: string
                reason:
                  type: string
              example:
                targetType: QUEUE
                targetRef: HARDSHIP
                reason: Specialist skill is required.
            example:
              targetType: QUEUE
              targetRef: HARDSHIP
              reason: Specialist skill is required.
  /v1/servicing/interactions:
    post:
      tags:
        - Interactions
      operationId: createInteraction
      summary: Create an interaction
      description: Logs an inbound, outbound, or external interaction; outbound commands run the execution-time compliance
        gate before provider submission.
      x-permission: CREATE_SERVICING_INTERACTION
      x-idempotent: true
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: Idempotency-Key
          in: header
          required: false
          description: Optional replay key for this logical mutation. Omission creates a fresh server-owned key for this attempt;
            blank, repeated, or longer-than-50-character values are rejected.
          schema:
            type: string
            minLength: 1
            maxLength: 50
      responses:
        "201":
          description: Created.
          content:
            application/json:
              schema:
                type: object
                required:
                  - interactionId
                  - status
                  - resourceId
                properties:
                  interactionId:
                    type: integer
                  status:
                    type: string
                    description: Current normalized lifecycle state.
                  resourceId:
                    type: integer
              example:
                interactionId: 3001
                status: COMPLETED
                resourceId: 3001
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
        "409":
          $ref: "#/components/responses/Servicing409Error"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - customerRef
                - channel
                - direction
                - verificationState
                - contentSummary
              properties:
                customerRef:
                  type: string
                caseId:
                  type: integer
                  description: Stable opaque servicing case identifier.
                channel:
                  type: string
                direction:
                  type: string
                reasonCode:
                  type: string
                  description: Configured structured reason code.
                verificationState:
                  type: string
                contentSummary:
                  type: string
              example:
                customerRef: "123"
                caseId: 1001
                channel: EMAIL
                direction: INBOUND
                reasonCode: PAYMENT_QUESTION
                verificationState: NOT_APPLICABLE
                contentSummary: Customer asks why a payment did not post.
            example:
              customerRef: "123"
              caseId: 1001
              channel: EMAIL
              direction: INBOUND
              reasonCode: PAYMENT_QUESTION
              verificationState: NOT_APPLICABLE
              contentSummary: Customer asks why a payment did not post.
    get:
      tags:
        - Interactions
      operationId: listInteractions
      summary: List interactions
      description: Lists permission-filtered interactions with focused channel, state, case, customer, keyword, and time filters.
      x-permission: READ_SERVICING_INTERACTION
      x-idempotent: false
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: customerRef
          in: query
          required: false
          description: Exact customer reference.
          schema:
            type: string
        - name: caseId
          in: query
          required: false
          description: Exact case ID.
          schema:
            type: integer
        - name: channel
          in: query
          required: false
          description: Repeat to include multiple channels.
          schema:
            type: string
        - name: status
          in: query
          required: false
          description: Repeat to include multiple interaction states.
          schema:
            type: string
        - name: reasonCode
          in: query
          required: false
          description: Exact reason code.
          schema:
            type: string
        - name: direction
          in: query
          required: false
          description: Interaction direction.
          schema:
            type: string
        - name: interactionType
          in: query
          required: false
          description: Interaction type.
          schema:
            type: string
        - name: sensitive
          in: query
          required: false
          description: Filter by sensitivity.
          schema:
            type: boolean
        - name: missedCall
          in: query
          required: false
          description: Filter missed-call work.
          schema:
            type: boolean
        - name: recordingState
          in: query
          required: false
          description: Exact recording state.
          schema:
            type: string
        - name: keyword
          in: query
          required: false
          description: Focused 2-200 character interaction keyword.
          schema:
            type: string
        - name: createdFrom
          in: query
          required: false
          description: Inclusive timestamp lower bound.
          schema:
            type: string
            format: date-time
        - name: createdTo
          in: query
          required: false
          description: Exclusive timestamp upper bound.
          schema:
            type: string
            format: date-time
        - name: limit
          in: query
          required: false
          description: Maximum rows to return; defaults to 50.
          schema:
            type: integer
            minimum: 1
            maximum: 200
            default: 50
        - name: offset
          in: query
          required: false
          description: Zero-based row offset; defaults to 0.
          schema:
            type: integer
            minimum: 0
            default: 0
        - name: sort
          in: query
          required: false
          description: Allowlisted sort field for this collection.
          schema:
            type: string
        - name: order
          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:
                  - items
                  - limit
                  - offset
                  - hasMore
                properties:
                  items:
                    type: array
                    items:
                      type: object
                      required:
                        - interactionId
                        - customerRef
                        - caseId
                        - channel
                        - direction
                        - interactionType
                        - reasonCode
                        - status
                        - verificationState
                        - contentSummary
                        - createdAt
                        - lastUpdatedAt
                        - lastActivityAt
                        - recordingState
                        - missedCall
                      properties:
                        interactionId:
                          type: integer
                        customerRef:
                          type: string
                        caseId:
                          type: integer
                          description: Stable opaque servicing case identifier.
                        channel:
                          type: string
                        direction:
                          type: string
                        interactionType:
                          type: string
                        reasonCode:
                          type: string
                          description: Configured structured reason code.
                        status:
                          type: string
                          description: Current normalized lifecycle state.
                        verificationState:
                          type: string
                        contentSummary:
                          type: string
                        createdAt:
                          type: string
                          format: date-time
                        lastUpdatedAt:
                          type: string
                          format: date-time
                        lastActivityAt:
                          type: string
                          format: date-time
                        recordingState:
                          type: string
                        missedCall:
                          type: boolean
                  limit:
                    type: integer
                  offset:
                    type: integer
                  hasMore:
                    type: boolean
              example:
                items:
                  - interactionId: 3001
                    customerRef: "123"
                    caseId: 1001
                    channel: EMAIL
                    direction: INBOUND
                    interactionType: MESSAGE
                    reasonCode: PAYMENT_QUESTION
                    status: COMPLETED
                    verificationState: NOT_APPLICABLE
                    contentSummary: Customer asks why a payment did not post.
                    createdAt: 2026-07-25T18:30:00Z
                    lastUpdatedAt: 2026-07-25T18:30:00Z
                    lastActivityAt: 2026-07-25T18:30:00Z
                    recordingState: NOT_RECORDED
                    missedCall: false
                limit: 50
                offset: 0
                hasMore: false
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
  /v1/servicing/interactions/{interactionId}:
    get:
      tags:
        - Interactions
      operationId: getInteraction
      summary: Retrieve an interaction
      description: Returns the presentation-safe interaction, outcomes, provenance, linked work, the embedded latest
        compliance decision, and the voice-call summary, without transcript or audio content.
      x-permission: READ_SERVICING_INTERACTION
      x-idempotent: false
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: interactionId
          in: path
          required: true
          description: Positive numeric interaction identifier.
          schema:
            type: integer
            format: int64
            minimum: 1
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - interactionId
                  - customerRef
                  - caseId
                  - channel
                  - direction
                  - interactionType
                  - reasonCode
                  - status
                  - verificationState
                  - contentSummary
                  - createdAt
                  - loanRef
                  - contactPointRef
                  - scheduledAt
                  - startedAt
                  - completedAt
                  - lastUpdatedAt
                  - primaryOutcomeCode
                  - secondaryOutcomeCodes
                  - transcriptAvailable
                  - recordingAvailable
                  - linkedTaskIds
                  - complianceDecision
                  - voiceCall
                properties:
                  interactionId:
                    type: integer
                  customerRef:
                    type: string
                  caseId:
                    type: integer
                    description: Stable opaque servicing case identifier.
                  channel:
                    type: string
                  direction:
                    type: string
                  interactionType:
                    type: string
                  reasonCode:
                    type: string
                    description: Configured structured reason code.
                  status:
                    type: string
                    description: Current normalized lifecycle state.
                  verificationState:
                    type: string
                  contentSummary:
                    type: string
                  createdAt:
                    type: string
                    format: date-time
                  loanRef:
                    type: string
                  contactPointRef:
                    type: string
                  scheduledAt:
                    type: string
                    format: date-time
                  startedAt:
                    type: string
                    format: date-time
                  completedAt:
                    type: string
                    format: date-time
                  lastUpdatedAt:
                    type: string
                    format: date-time
                  primaryOutcomeCode:
                    type: string
                  secondaryOutcomeCodes:
                    type: array
                    items:
                      type: object
                  transcriptAvailable:
                    type: boolean
                  recordingAvailable:
                    type: boolean
                  linkedTaskIds:
                    type: array
                    items:
                      type: integer
                  complianceDecision:
                    type: object
                    required:
                      - decisionId
                      - proposedAction
                      - outcome
                      - hardStop
                      - evaluatedAt
                      - rules
                    properties:
                      decisionId:
                        type: integer
                      proposedAction:
                        type: string
                      outcome:
                        type: string
                      hardStop:
                        type: boolean
                      evaluatedAt:
                        type: string
                        format: date-time
                      rules:
                        type: array
                        items:
                          type: object
                          required:
                            - ruleCode
                            - outcome
                          properties:
                            ruleCode:
                              type: string
                            outcome:
                              type: string
                  voiceCall:
                    type: object
                    required:
                      - callId
                      - gatewayCode
                      - status
                      - recordingState
                      - durationSeconds
                      - preDialComplianceDecisionId
                      - startedAt
                      - answeredAt
                      - completedAt
                      - dialAuthorizedAt
                      - dialAuthorizationExpiresAt
                    properties:
                      callId:
                        type: integer
                      gatewayCode:
                        type: string
                      status:
                        type: string
                        description: Current normalized lifecycle state.
                      recordingState:
                        type: string
                      durationSeconds:
                        type: integer
                      preDialComplianceDecisionId:
                        type: integer
                      startedAt:
                        type: string
                        format: date-time
                      answeredAt:
                        type: string
                        format: date-time
                      completedAt:
                        type: string
                        format: date-time
                      dialAuthorizedAt:
                        type: string
                        format: date-time
                      dialAuthorizationExpiresAt:
                        type: string
                        format: date-time
              example:
                interactionId: 3001
                customerRef: "123"
                caseId: 1001
                channel: PHONE
                direction: OUTBOUND
                interactionType: CALL
                reasonCode: COLLECTIONS_FOLLOW_UP
                status: COMPLETED
                verificationState: NOT_APPLICABLE
                contentSummary: Outbound collections call attempt.
                createdAt: 2026-07-25T18:30:00Z
                loanRef: "456"
                contactPointRef: phone-1
                scheduledAt: 2026-07-25T18:29:00Z
                startedAt: 2026-07-25T18:30:00Z
                completedAt: 2026-07-25T18:33:34Z
                lastUpdatedAt: 2026-07-25T18:33:34Z
                primaryOutcomeCode: CUSTOMER_REACHED
                secondaryOutcomeCodes: []
                transcriptAvailable: true
                recordingAvailable: false
                linkedTaskIds:
                  - 2001
                complianceDecision:
                  decisionId: 6117
                  proposedAction: OUTBOUND_CONTACT
                  outcome: ALLOWED
                  hardStop: false
                  evaluatedAt: 2026-07-25T18:29:58Z
                  rules:
                    - ruleCode: CONTACT_WINDOW_CA
                      outcome: ALLOWED
                voiceCall:
                  callId: 7001
                  gatewayCode: VOICE_GATEWAY_PRIMARY
                  status: COMPLETED
                  recordingState: NOT_RECORDED
                  durationSeconds: 214
                  preDialComplianceDecisionId: 6117
                  startedAt: 2026-07-25T18:30:00Z
                  answeredAt: 2026-07-25T18:30:09Z
                  completedAt: 2026-07-25T18:33:34Z
                  dialAuthorizedAt: 2026-07-25T18:29:58Z
                  dialAuthorizationExpiresAt: 2026-07-25T18:30:28Z
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
  /v1/servicing/cases/{caseId}/promises:
    post:
      tags:
        - Promises
      operationId: createPromise
      summary: Create a promise to pay
      description: Creates an in-policy promise immediately or materializes the exact approval request when terms exceed
        configured guardrails. A promise never authorizes a debit.
      x-permission: CREATE_SERVICING_PROMISE
      x-idempotent: true
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: caseId
          in: path
          required: true
          description: Positive numeric case identifier.
          schema:
            type: integer
            format: int64
            minimum: 1
        - name: Idempotency-Key
          in: header
          required: false
          description: Optional replay key for this logical mutation. Omission creates a fresh server-owned key for this attempt;
            blank, repeated, or longer-than-50-character values are rejected.
          schema:
            type: string
            minLength: 1
            maxLength: 50
      responses:
        "201":
          description: Created.
          content:
            application/json:
              schema:
                type: object
                required:
                  - outcome
                  - promise
                  - resourceId
                properties:
                  outcome:
                    type: string
                  promise:
                    type: object
                    required:
                      - promiseId
                      - loanRef
                      - planType
                      - state
                      - amount
                      - promiseDate
                      - reason
                      - evaluatedAgainstAsOf
                      - createdAt
                    properties:
                      promiseId:
                        type: integer
                      loanRef:
                        type: string
                      planType:
                        type: string
                      state:
                        type: string
                      amount:
                        type: object
                        description: Decimal monetary value using the representation declared by this operation.
                        required:
                          - amount
                          - currency
                        properties:
                          amount:
                            type: integer
                            description: Decimal monetary value using the representation declared by this operation.
                          currency:
                            type: string
                            pattern: ^[A-Z]{3}$
                            description: ISO 4217 currency code.
                      promiseDate:
                        type: string
                        format: date
                      reason:
                        type: string
                      evaluatedAgainstAsOf:
                        type: string
                      createdAt:
                        type: string
                        format: date-time
                  resourceId:
                    type: integer
              example:
                outcome: COMPLETED
                promise:
                  promiseId: 6101
                  loanRef: "456"
                  planType: SINGLE
                  state: ACTIVE
                  amount:
                    amount: 250
                    currency: USD
                  promiseDate: 2026-08-01
                  reason: Customer committed to pay on 2026-08-01.
                  evaluatedAgainstAsOf: 2026-07-25T18:30:00Z
                  createdAt: 2026-07-25T18:30:00Z
                resourceId: 6101
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
        "409":
          $ref: "#/components/responses/Servicing409Error"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - loanRef
                - planType
                - reason
              properties:
                loanRef:
                  type: string
                planType:
                  type: string
                promiseDate:
                  type: string
                  format: date
                promiseAmount:
                  type: object
                  required:
                    - amount
                    - currency
                  properties:
                    amount:
                      type: integer
                      description: Decimal monetary value using the representation declared by this operation.
                    currency:
                      type: string
                      pattern: ^[A-Z]{3}$
                      description: ISO 4217 currency code.
                reason:
                  type: string
                evidenceIds:
                  type: array
                  description: Evidence records supporting the request.
                  items:
                    type: integer
              example:
                loanRef: "456"
                planType: SINGLE
                promiseDate: 2026-08-01
                promiseAmount:
                  amount: 250
                  currency: USD
                reason: Customer committed to pay on 2026-08-01.
                evidenceIds:
                  - 8801
            example:
              loanRef: "456"
              planType: SINGLE
              promiseDate: 2026-08-01
              promiseAmount:
                amount: 250
                currency: USD
              reason: Customer committed to pay on 2026-08-01.
              evidenceIds:
                - 8801
    get:
      tags:
        - Promises
      operationId: listPromises
      summary: List case promises
      description: Lists case promises and returns the current guardrail bounds used by the servicing workspace.
      x-permission: READ_SERVICING_CASE
      x-idempotent: false
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: caseId
          in: path
          required: true
          description: Positive numeric case identifier.
          schema:
            type: integer
            format: int64
            minimum: 1
        - name: limit
          in: query
          required: false
          description: Maximum rows to return; defaults to 50.
          schema:
            type: integer
            minimum: 1
            maximum: 200
            default: 50
        - name: offset
          in: query
          required: false
          description: Zero-based row offset; defaults to 0.
          schema:
            type: integer
            minimum: 0
            default: 0
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - items
                  - guardrail
                  - limit
                  - offset
                  - hasMore
                properties:
                  items:
                    type: array
                    items:
                      type: object
                      required:
                        - promiseId
                        - loanRef
                        - planType
                        - state
                        - amount
                        - promiseDate
                        - reason
                        - evaluatedAgainstAsOf
                        - createdAt
                      properties:
                        promiseId:
                          type: integer
                        loanRef:
                          type: string
                        planType:
                          type: string
                        state:
                          type: string
                        amount:
                          type: object
                          description: Decimal monetary value using the representation declared by this operation.
                          required:
                            - amount
                            - currency
                          properties:
                            amount:
                              type: integer
                              description: Decimal monetary value using the representation declared by this operation.
                            currency:
                              type: string
                              pattern: ^[A-Z]{3}$
                              description: ISO 4217 currency code.
                        promiseDate:
                          type: string
                          format: date
                        reason:
                          type: string
                        evaluatedAgainstAsOf:
                          type: string
                        createdAt:
                          type: string
                          format: date-time
                  guardrail:
                    type: object
                    required:
                      - maxHorizonDays
                      - minAmountPercent
                      - maxInstallments
                      - outOfBoundsApprovalRole
                    properties:
                      maxHorizonDays:
                        type: integer
                      minAmountPercent:
                        type: integer
                      maxInstallments:
                        type: integer
                      outOfBoundsApprovalRole:
                        type: string
                  limit:
                    type: integer
                  offset:
                    type: integer
                  hasMore:
                    type: boolean
              example:
                items:
                  - promiseId: 6101
                    loanRef: "456"
                    planType: SINGLE
                    state: ACTIVE
                    amount:
                      amount: 250
                      currency: USD
                    promiseDate: 2026-08-01
                    reason: Customer committed to pay on 2026-08-01.
                    evaluatedAgainstAsOf: 2026-07-25T18:30:00Z
                    createdAt: 2026-07-25T18:30:00Z
                guardrail:
                  maxHorizonDays: 30
                  minAmountPercent: 25
                  maxInstallments: 4
                  outOfBoundsApprovalRole: SUPERVISOR
                limit: 50
                offset: 0
                hasMore: false
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
  /v1/servicing/action-requests/{actionRequestId}:
    get:
      tags:
        - Action requests
      operationId: getActionRequest
      summary: Retrieve an action request
      description: Returns the typed request, safe lifecycle/result state, and the caller-specific allowed actions needed by
        the case workspace and approver.
      x-permission: READ_SERVICING_ACTION_REQUEST
      x-idempotent: false
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: actionRequestId
          in: path
          required: true
          description: Positive numeric actionRequest identifier.
          schema:
            type: integer
            format: int64
            minimum: 1
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - actionRequestId
                  - externalActionRef
                  - caseId
                  - externalCaseRef
                  - customerRef
                  - actionType
                  - riskClass
                  - status
                  - preparedByActorType
                  - preparedByWorkerId
                  - approvalRequired
                  - approvalPermissionCode
                  - allowedActions
                  - requestPayload
                  - createdAt
                  - lastUpdatedAt
                properties:
                  actionRequestId:
                    type: integer
                    description: Stable opaque action-request identifier.
                  externalActionRef:
                    type: string
                  caseId:
                    type: integer
                    description: Stable opaque servicing case identifier.
                  externalCaseRef:
                    type: string
                  customerRef:
                    type: string
                  actionType:
                    type: string
                  riskClass:
                    type: string
                  status:
                    type: string
                    description: Current normalized lifecycle state.
                  preparedByActorType:
                    type: string
                  preparedByWorkerId:
                    type: integer
                  approvalRequired:
                    type: boolean
                  approvalPermissionCode:
                    type: string
                  allowedActions:
                    type: array
                    items:
                      type: string
                  requestPayload:
                    type: object
                    required:
                      - loanRef
                      - planType
                      - promiseDate
                    properties:
                      loanRef:
                        type: string
                      planType:
                        type: string
                      promiseDate:
                        type: string
                        format: date
                  createdAt:
                    type: string
                    format: date-time
                  lastUpdatedAt:
                    type: string
                    format: date-time
              example:
                actionRequestId: 6001
                externalActionRef: LE-ACTION-6001
                caseId: 1001
                externalCaseRef: LE-CASE-1001
                customerRef: "123"
                actionType: AR_002
                riskClass: R2
                status: APPROVAL_REQUIRED
                preparedByActorType: HUMAN
                preparedByWorkerId: 4101
                approvalRequired: true
                approvalPermissionCode: APPROVE_SERVICING_PROMISE
                allowedActions:
                  - APPROVE
                  - REJECT
                requestPayload:
                  loanRef: "456"
                  planType: SINGLE
                  promiseDate: 2026-08-01
                createdAt: 2026-07-25T18:30:00Z
                lastUpdatedAt: 2026-07-25T18:30:00Z
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
  /v1/servicing/action-requests/{actionRequestId}/approve:
    post:
      tags:
        - Action requests
      operationId: approveActionRequest
      summary: Approve an action request
      description: Approves a request using its server-derived action-specific approval permission and maker-not-approver checks.
      x-permission: APPROVE_SERVICING_ACTION_REQUEST
      x-idempotent: true
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: actionRequestId
          in: path
          required: true
          description: Positive numeric actionRequest identifier.
          schema:
            type: integer
            format: int64
            minimum: 1
        - name: Idempotency-Key
          in: header
          required: false
          description: Optional replay key for this logical mutation. Omission creates a fresh server-owned key for this attempt;
            blank, repeated, or longer-than-50-character values are rejected.
          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:
                      - status
                    properties:
                      status:
                        type: string
                        description: Current normalized lifecycle state.
              example:
                resourceId: 6001
                changes:
                  status: APPROVED
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
        "409":
          $ref: "#/components/responses/Servicing409Error"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - decisionNote
              properties:
                decisionNote:
                  type: string
                evidenceIds:
                  type: array
                  description: Evidence records supporting the request.
                  items:
                    type: integer
              example:
                decisionNote: Terms are appropriate for the documented customer circumstances.
                evidenceIds:
                  - 8801
            example:
              decisionNote: Terms are appropriate for the documented customer circumstances.
              evidenceIds:
                - 8801
      x-authorization-note: The service also re-derives and requires the action-specific APPROVE_SERVICING_<ACTION> permission.
  /v1/servicing/action-requests/{actionRequestId}/reject:
    post:
      tags:
        - Action requests
      operationId: rejectActionRequest
      summary: Reject an action request
      description: Rejects a pending request using the same server-derived action-specific approval authority.
      x-permission: REJECT_SERVICING_ACTION_REQUEST
      x-idempotent: true
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: actionRequestId
          in: path
          required: true
          description: Positive numeric actionRequest identifier.
          schema:
            type: integer
            format: int64
            minimum: 1
        - name: Idempotency-Key
          in: header
          required: false
          description: Optional replay key for this logical mutation. Omission creates a fresh server-owned key for this attempt;
            blank, repeated, or longer-than-50-character values are rejected.
          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:
                      - status
                    properties:
                      status:
                        type: string
                        description: Current normalized lifecycle state.
              example:
                resourceId: 6001
                changes:
                  status: REJECTED
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
        "409":
          $ref: "#/components/responses/Servicing409Error"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - reason
              properties:
                reason:
                  type: string
                evidenceIds:
                  type: array
                  description: Evidence records supporting the request.
                  items:
                    type: integer
              example:
                reason: The supplied evidence does not support the requested exception.
                evidenceIds:
                  - 8801
            example:
              reason: The supplied evidence does not support the requested exception.
              evidenceIds:
                - 8801
      x-authorization-note: The service also re-derives and requires the action-specific APPROVE_SERVICING_<ACTION> permission.
  /v1/servicing/action-requests/{actionRequestId}/submit:
    post:
      tags:
        - Action requests
      operationId: submitActionRequest
      summary: Submit an approved action request
      description: Executes immutable approved inputs through the typed owning boundary. This command accepts no request body.
      x-permission: SUBMIT_SERVICING_ACTION_REQUEST
      x-idempotent: true
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: actionRequestId
          in: path
          required: true
          description: Positive numeric actionRequest identifier.
          schema:
            type: integer
            format: int64
            minimum: 1
        - name: Idempotency-Key
          in: header
          required: false
          description: Optional replay key for this logical mutation. Omission creates a fresh server-owned key for this attempt;
            blank, repeated, or longer-than-50-character values are rejected.
          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:
                      - status
                    properties:
                      status:
                        type: string
                        description: Current normalized lifecycle state.
              example:
                resourceId: 6001
                changes:
                  status: SUBMITTED
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
        "409":
          $ref: "#/components/responses/Servicing409Error"
  /v1/servicing/cases/{caseId}/documents:
    post:
      tags:
        - Case documents
      operationId: registerCaseDocument
      summary: Upload a case document
      description: Registers metadata and binary content through one controlled multipart intake, then creates scan/review
        work before use.
      x-permission: CREATE_SERVICING_DOCUMENT
      x-idempotent: true
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: caseId
          in: path
          required: true
          description: Positive numeric case identifier.
          schema:
            type: integer
            format: int64
            minimum: 1
        - name: Idempotency-Key
          in: header
          required: false
          description: Optional replay key for this logical mutation. Omission creates a fresh server-owned key for this attempt;
            blank, repeated, or longer-than-50-character values are rejected.
          schema:
            type: string
            minLength: 1
            maxLength: 50
      responses:
        "201":
          description: Created.
          content:
            application/json:
              schema:
                type: object
                required:
                  - documentId
                  - status
                  - reviewTaskId
                  - links
                  - resourceId
                properties:
                  documentId:
                    type: integer
                  status:
                    type: string
                    description: Current normalized lifecycle state.
                  reviewTaskId:
                    type: integer
                  links:
                    type: array
                    items:
                      type: object
                      required:
                        - targetType
                        - targetRef
                      properties:
                        targetType:
                          type: string
                        targetRef:
                          type: string
                  resourceId:
                    type: integer
              example:
                documentId: 7001
                status: PENDING_REVIEW
                reviewTaskId: 3301
                links:
                  - targetType: CASE
                    targetRef: "1001"
                  - targetType: CUSTOMER
                    targetRef: "123"
                  - targetType: LOAN
                    targetRef: "456"
                resourceId: 7001
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
        "409":
          $ref: "#/components/responses/Servicing409Error"
      requestBody:
        required: true
        content:
          multipart/form-data:
            schema:
              type: object
              properties:
                file:
                  type: string
                  format: binary
                  description: The document bytes. PDF, JPEG, or PNG up to the configured size ceiling.
              required:
                - file
    get:
      tags:
        - Case documents
      operationId: listCaseDocuments
      summary: List case documents
      description: Lists case-linked document projections, including restricted metadata for sensitive items and active review work.
      x-permission: READ_SERVICING_DOCUMENT
      x-idempotent: false
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: caseId
          in: path
          required: true
          description: Positive numeric case identifier.
          schema:
            type: integer
            format: int64
            minimum: 1
        - name: reviewStatus
          in: query
          required: false
          description: Exact review state.
          schema:
            type: string
        - name: documentType
          in: query
          required: false
          description: Exact document type.
          schema:
            type: string
        - name: origin
          in: query
          required: false
          description: Exact intake origin.
          schema:
            type: string
        - name: scanStatus
          in: query
          required: false
          description: Exact scan state.
          schema:
            type: string
        - name: sensitive
          in: query
          required: false
          description: Filter by sensitivity.
          schema:
            type: boolean
        - name: createdFrom
          in: query
          required: false
          description: Inclusive timestamp lower bound.
          schema:
            type: string
            format: date-time
        - name: createdTo
          in: query
          required: false
          description: Exclusive timestamp upper bound.
          schema:
            type: string
            format: date-time
        - name: limit
          in: query
          required: false
          description: Maximum rows to return; defaults to 50.
          schema:
            type: integer
            minimum: 1
            maximum: 200
            default: 50
        - name: offset
          in: query
          required: false
          description: Zero-based row offset; defaults to 0.
          schema:
            type: integer
            minimum: 0
            default: 0
        - name: sort
          in: query
          required: false
          description: Allowlisted sort field for this collection.
          schema:
            type: string
        - name: order
          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:
                  - items
                  - limit
                  - offset
                  - hasMore
                properties:
                  items:
                    type: array
                    items:
                      type: object
                      required:
                        - documentId
                        - title
                        - documentType
                        - origin
                        - scanStatus
                        - reviewStatus
                        - sensitive
                        - links
                        - createdAt
                      properties:
                        documentId:
                          type: integer
                        title:
                          type: string
                        documentType:
                          type: string
                        origin:
                          type: string
                        scanStatus:
                          type: string
                        reviewStatus:
                          type: string
                        sensitive:
                          type: boolean
                        links:
                          type: array
                          items:
                            type: object
                            required:
                              - targetType
                              - targetRef
                            properties:
                              targetType:
                                type: string
                              targetRef:
                                type: string
                        createdAt:
                          type: string
                          format: date-time
                  limit:
                    type: integer
                  offset:
                    type: integer
                  hasMore:
                    type: boolean
              example:
                items:
                  - documentId: 7001
                    title: Bankruptcy notice filed June 14
                    documentType: BANKRUPTCY_NOTICE
                    origin: BORROWER_UPLOAD
                    scanStatus: CLEAN
                    reviewStatus: ACCEPTED
                    sensitive: true
                    links:
                      - targetType: CASE
                        targetRef: "1001"
                      - targetType: CUSTOMER
                        targetRef: "123"
                      - targetType: LOAN
                        targetRef: "456"
                    createdAt: 2026-07-25T18:30:00Z
                limit: 50
                offset: 0
                hasMore: false
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
  /v1/servicing/documents/{documentId}:
    get:
      tags:
        - Case documents
      operationId: getCaseDocument
      summary: Retrieve case document metadata
      description: Returns the authorized document projection, lifecycle, scan/review state, links, and safe integrity metadata.
      x-permission: READ_SERVICING_DOCUMENT
      x-idempotent: false
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: documentId
          in: path
          required: true
          description: Positive numeric document identifier.
          schema:
            type: integer
            format: int64
            minimum: 1
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - documentId
                  - title
                  - documentType
                  - origin
                  - scanStatus
                  - reviewStatus
                  - sensitive
                  - links
                  - createdAt
                properties:
                  documentId:
                    type: integer
                  title:
                    type: string
                  documentType:
                    type: string
                  origin:
                    type: string
                  scanStatus:
                    type: string
                  reviewStatus:
                    type: string
                  sensitive:
                    type: boolean
                  links:
                    type: array
                    items:
                      type: object
                      required:
                        - targetType
                        - targetRef
                      properties:
                        targetType:
                          type: string
                        targetRef:
                          type: string
                  createdAt:
                    type: string
                    format: date-time
              example:
                documentId: 7001
                title: Bankruptcy notice filed June 14
                documentType: BANKRUPTCY_NOTICE
                origin: BORROWER_UPLOAD
                scanStatus: CLEAN
                reviewStatus: ACCEPTED
                sensitive: true
                links:
                  - targetType: CASE
                    targetRef: "1001"
                  - targetType: CUSTOMER
                    targetRef: "123"
                  - targetType: LOAN
                    targetRef: "456"
                createdAt: 2026-07-25T18:30:00Z
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
    put:
      tags:
        - Case documents
      operationId: updateCaseDocument
      summary: Correct document metadata
      description: Corrects approved metadata without changing content, origin, checksum, review evidence, or links.
      x-permission: UPDATE_SERVICING_DOCUMENT
      x-idempotent: true
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: documentId
          in: path
          required: true
          description: Positive numeric document identifier.
          schema:
            type: integer
            format: int64
            minimum: 1
        - name: Idempotency-Key
          in: header
          required: false
          description: Optional replay key for this logical mutation. Omission creates a fresh server-owned key for this attempt;
            blank, repeated, or longer-than-50-character values are rejected.
          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
                    properties:
                      title:
                        type: string
              example:
                resourceId: 7001
                changes:
                  title: Bankruptcy notice - corrected label
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
        "409":
          $ref: "#/components/responses/Servicing409Error"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - reason
              properties:
                title:
                  type: string
                reason:
                  type: string
              example:
                title: Bankruptcy notice - corrected label
                reason: Corrected the intake title after review.
            example:
              title: Bankruptcy notice - corrected label
              reason: Corrected the intake title after review.
  /v1/servicing/documents/{documentId}/review:
    post:
      tags:
        - Case documents
      operationId: reviewCaseDocument
      summary: Review a case document
      description: Accepts or rejects scanned content, finalizes classification and links, and optionally promotes it to evidence.
      x-permission: REVIEW_SERVICING_DOCUMENT
      x-idempotent: true
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: documentId
          in: path
          required: true
          description: Positive numeric document identifier.
          schema:
            type: integer
            format: int64
            minimum: 1
        - name: Idempotency-Key
          in: header
          required: false
          description: Optional replay key for this logical mutation. Omission creates a fresh server-owned key for this attempt;
            blank, repeated, or longer-than-50-character values are rejected.
          schema:
            type: string
            minLength: 1
            maxLength: 50
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - documentId
                  - reviewStatus
                  - links
                  - evidenceId
                  - reviewTaskId
                  - resourceId
                properties:
                  documentId:
                    type: integer
                  reviewStatus:
                    type: string
                  links:
                    type: array
                    items:
                      type: object
                      required:
                        - targetType
                        - targetRef
                      properties:
                        targetType:
                          type: string
                        targetRef:
                          type: string
                  evidenceId:
                    type: integer
                  reviewTaskId:
                    type: integer
                  resourceId:
                    type: integer
              example:
                documentId: 7001
                reviewStatus: ACCEPTED
                links:
                  - targetType: CASE
                    targetRef: "1001"
                  - targetType: CUSTOMER
                    targetRef: "123"
                  - targetType: LOAN
                    targetRef: "456"
                evidenceId: 8801
                reviewTaskId: 3301
                resourceId: 7001
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
        "409":
          $ref: "#/components/responses/Servicing409Error"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - outcome
              properties:
                outcome:
                  type: string
                documentType:
                  type: string
                sensitive:
                  type: boolean
                loanRefs:
                  type: array
                  items:
                    type: string
                promoteToEvidence:
                  type: boolean
                reviewNote:
                  type: string
              example:
                outcome: ACCEPTED
                documentType: BANKRUPTCY_NOTICE
                sensitive: true
                loanRefs:
                  - "456"
                promoteToEvidence: true
                reviewNote: Customer identity and filing reference verified.
            example:
              outcome: ACCEPTED
              documentType: BANKRUPTCY_NOTICE
              sensitive: true
              loanRefs:
                - "456"
              promoteToEvidence: true
              reviewNote: Customer identity and filing reference verified.
  /v1/servicing/users:
    get:
      tags:
        - Workforce
      operationId: listServicingUsers
      summary: List servicing users
      description: Lists composed human login and servicing-worker profiles using declared filters and offset pagination.
      x-permission: READ_SERVICING_USER
      x-idempotent: false
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: active
          in: query
          required: false
          description: Filter by active state.
          schema:
            type: boolean
        - name: officeId
          in: query
          required: false
          description: Filter by public office ID.
          schema:
            type: integer
        - name: roleId
          in: query
          required: false
          description: Filter by assigned role ID.
          schema:
            type: integer
        - name: queueCode
          in: query
          required: false
          description: Filter by servicing queue membership.
          schema:
            type: string
        - name: limit
          in: query
          required: false
          description: Maximum rows to return; defaults to 50.
          schema:
            type: integer
            minimum: 1
            maximum: 200
            default: 50
        - name: offset
          in: query
          required: false
          description: Zero-based row offset; defaults to 0.
          schema:
            type: integer
            minimum: 0
            default: 0
        - name: sort
          in: query
          required: false
          description: Allowlisted sort field for this collection.
          schema:
            type: string
        - name: order
          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:
                  - items
                  - limit
                  - offset
                  - hasMore
                properties:
                  items:
                    type: array
                    items:
                      type: object
                      required:
                        - userId
                        - username
                        - displayName
                        - email
                        - officeId
                        - roleIds
                        - active
                        - credentialResetRequired
                        - workerProfile
                        - lastModifiedAt
                      properties:
                        userId:
                          type: integer
                        username:
                          type: string
                        displayName:
                          type: string
                        email:
                          type: string
                        officeId:
                          type: integer
                        roleIds:
                          type: array
                          items:
                            type: integer
                        active:
                          type: boolean
                        credentialResetRequired:
                          type: boolean
                        workerProfile:
                          type: object
                          required:
                            - queueCodes
                            - taskTypeCodes
                            - skills
                            - languages
                            - capacity
                          properties:
                            queueCodes:
                              type: array
                              items:
                                type: string
                            taskTypeCodes:
                              type: array
                              items:
                                type: string
                            skills:
                              type: array
                              items:
                                type: string
                            languages:
                              type: array
                              items:
                                type: string
                            capacity:
                              type: integer
                        lastModifiedAt:
                          type: string
                          format: date-time
                  limit:
                    type: integer
                  offset:
                    type: integer
                  hasMore:
                    type: boolean
              example:
                items:
                  - userId: 4101
                    username: maria.agent
                    displayName: Maria Agent
                    email: maria@example.invalid
                    officeId: 1
                    roleIds:
                      - 7
                    active: true
                    credentialResetRequired: true
                    workerProfile:
                      queueCodes:
                        - COLLECTIONS
                      taskTypeCodes:
                        - COLLECTIONS_OUTREACH
                      skills:
                        - COLLECTIONS
                      languages:
                        - en
                      capacity: 8
                    lastModifiedAt: 2026-07-25T18:30:00Z
                limit: 50
                offset: 0
                hasMore: false
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
    post:
      tags:
        - Workforce
      operationId: createServicingUser
      summary: Create a servicing user
      description: Atomically creates the human login, HUMAN worker, presence, and queue/task eligibility profile.
      x-permission: CREATE_SERVICING_USER
      x-idempotent: true
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: Idempotency-Key
          in: header
          required: false
          description: Optional replay key for this logical mutation. Omission creates a fresh server-owned key for this attempt;
            blank, repeated, or longer-than-50-character values are rejected.
          schema:
            type: string
            minLength: 1
            maxLength: 50
      responses:
        "201":
          description: Created.
          content:
            application/json:
              schema:
                type: object
                required:
                  - userId
                  - username
                  - displayName
                  - active
                  - resourceId
                properties:
                  userId:
                    type: integer
                  username:
                    type: string
                  displayName:
                    type: string
                  active:
                    type: boolean
                  resourceId:
                    type: integer
              example:
                userId: 4101
                username: maria.agent
                displayName: Maria Agent
                active: true
                resourceId: 4101
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
        "409":
          $ref: "#/components/responses/Servicing409Error"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - username
                - temporaryPassword
                - firstName
                - lastName
                - email
                - officeId
                - roleIds
              properties:
                username:
                  type: string
                temporaryPassword:
                  type: string
                firstName:
                  type: string
                lastName:
                  type: string
                email:
                  type: string
                officeId:
                  type: integer
                roleIds:
                  type: array
                  items:
                    type: integer
                workerProfile:
                  type: object
                  required:
                    - queueCodes
                    - taskTypeCodes
                    - skills
                    - languages
                    - capacity
                  properties:
                    queueCodes:
                      type: array
                      items:
                        type: string
                    taskTypeCodes:
                      type: array
                      items:
                        type: string
                    skills:
                      type: array
                      items:
                        type: string
                    languages:
                      type: array
                      items:
                        type: string
                    capacity:
                      type: integer
              example:
                username: maria.agent
                temporaryPassword: <write-only>
                firstName: Maria
                lastName: Agent
                email: maria@example.invalid
                officeId: 1
                roleIds:
                  - 7
                workerProfile:
                  queueCodes:
                    - COLLECTIONS
                  taskTypeCodes:
                    - COLLECTIONS_OUTREACH
                  skills:
                    - COLLECTIONS
                  languages:
                    - en
                  capacity: 8
            example:
              username: maria.agent
              temporaryPassword: <write-only>
              firstName: Maria
              lastName: Agent
              email: maria@example.invalid
              officeId: 1
              roleIds:
                - 7
              workerProfile:
                queueCodes:
                  - COLLECTIONS
                taskTypeCodes:
                  - COLLECTIONS_OUTREACH
                skills:
                  - COLLECTIONS
                languages:
                  - en
                capacity: 8
  /v1/servicing/users/{userId}:
    get:
      tags:
        - Workforce
      operationId: getServicingUser
      summary: Retrieve a servicing user
      description: Returns one safe composed user projection without internal login keys or credential material.
      x-permission: READ_SERVICING_USER
      x-idempotent: false
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: userId
          in: path
          required: true
          description: Positive numeric user identifier.
          schema:
            type: integer
            format: int64
            minimum: 1
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - userId
                  - username
                  - displayName
                  - email
                  - officeId
                  - roleIds
                  - active
                  - credentialResetRequired
                  - workerProfile
                  - lastModifiedAt
                properties:
                  userId:
                    type: integer
                  username:
                    type: string
                  displayName:
                    type: string
                  email:
                    type: string
                  officeId:
                    type: integer
                  roleIds:
                    type: array
                    items:
                      type: integer
                  active:
                    type: boolean
                  credentialResetRequired:
                    type: boolean
                  workerProfile:
                    type: object
                    required:
                      - queueCodes
                      - taskTypeCodes
                      - skills
                      - languages
                      - capacity
                    properties:
                      queueCodes:
                        type: array
                        items:
                          type: string
                      taskTypeCodes:
                        type: array
                        items:
                          type: string
                      skills:
                        type: array
                        items:
                          type: string
                      languages:
                        type: array
                        items:
                          type: string
                      capacity:
                        type: integer
                  lastModifiedAt:
                    type: string
                    format: date-time
              example:
                userId: 4101
                username: maria.agent
                displayName: Maria Agent
                email: maria@example.invalid
                officeId: 1
                roleIds:
                  - 7
                active: true
                credentialResetRequired: true
                workerProfile:
                  queueCodes:
                    - COLLECTIONS
                  taskTypeCodes:
                    - COLLECTIONS_OUTREACH
                  skills:
                    - COLLECTIONS
                  languages:
                    - en
                  capacity: 8
                lastModifiedAt: 2026-07-25T18:30:00Z
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
    put:
      tags:
        - Workforce
      operationId: replaceServicingUser
      summary: Replace a servicing user profile
      description: Replaces mutable login administration and worker-profile fields; username and public user ID remain immutable.
      x-permission: UPDATE_SERVICING_USER
      x-idempotent: true
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: userId
          in: path
          required: true
          description: Positive numeric user identifier.
          schema:
            type: integer
            format: int64
            minimum: 1
        - name: Idempotency-Key
          in: header
          required: false
          description: Optional replay key for this logical mutation. Omission creates a fresh server-owned key for this attempt;
            blank, repeated, or longer-than-50-character values are rejected.
          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
                      - workerProfileUpdated
                    properties:
                      active:
                        type: boolean
                      workerProfileUpdated:
                        type: boolean
              example:
                resourceId: 4101
                changes:
                  active: true
                  workerProfileUpdated: true
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
        "409":
          $ref: "#/components/responses/Servicing409Error"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - firstName
                - lastName
                - email
                - officeId
                - roleIds
                - active
                - workerProfile
              properties:
                firstName:
                  type: string
                lastName:
                  type: string
                email:
                  type: string
                officeId:
                  type: integer
                roleIds:
                  type: array
                  items:
                    type: integer
                active:
                  type: boolean
                workerProfile:
                  type: object
                  required:
                    - queueCodes
                    - taskTypeCodes
                    - skills
                    - languages
                    - capacity
                  properties:
                    queueCodes:
                      type: array
                      items:
                        type: string
                    taskTypeCodes:
                      type: array
                      items:
                        type: string
                    skills:
                      type: array
                      items:
                        type: string
                    languages:
                      type: array
                      items:
                        type: string
                    capacity:
                      type: integer
              example:
                firstName: Maria
                lastName: Agent
                email: maria@example.invalid
                officeId: 1
                roleIds:
                  - 7
                active: true
                workerProfile:
                  queueCodes:
                    - COLLECTIONS
                  taskTypeCodes:
                    - COLLECTIONS_OUTREACH
                  skills:
                    - COLLECTIONS
                  languages:
                    - en
                  capacity: 8
            example:
              firstName: Maria
              lastName: Agent
              email: maria@example.invalid
              officeId: 1
              roleIds:
                - 7
              active: true
              workerProfile:
                queueCodes:
                  - COLLECTIONS
                taskTypeCodes:
                  - COLLECTIONS_OUTREACH
                skills:
                  - COLLECTIONS
                languages:
                  - en
                capacity: 8
  /v1/servicing/workers:
    get:
      tags:
        - Workforce
      operationId: listAiWorkers
      summary: List AI worker registrations
      description: Lists safe AI worker registrations; HUMAN and SYSTEM workers are not returned by this resource.
      x-permission: READ_SERVICING_WORKER
      x-idempotent: false
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: active
          in: query
          required: false
          description: Filter by active state.
          schema:
            type: boolean
        - name: adapterCode
          in: query
          required: false
          description: Filter by registered adapter code.
          schema:
            type: string
        - name: queueCode
          in: query
          required: false
          description: Filter by queue eligibility.
          schema:
            type: string
        - name: taskTypeCode
          in: query
          required: false
          description: Filter by task-type eligibility.
          schema:
            type: string
        - name: limit
          in: query
          required: false
          description: Maximum rows to return; defaults to 50.
          schema:
            type: integer
            minimum: 1
            maximum: 200
            default: 50
        - name: offset
          in: query
          required: false
          description: Zero-based row offset; defaults to 0.
          schema:
            type: integer
            minimum: 0
            default: 0
        - name: sort
          in: query
          required: false
          description: Allowlisted sort field for this collection.
          schema:
            type: string
        - name: order
          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:
                  - items
                  - limit
                  - offset
                  - hasMore
                properties:
                  items:
                    type: array
                    items:
                      type: object
                      required:
                        - workerId
                        - workerCode
                        - displayName
                        - adapterCode
                        - contractVersion
                        - queueCodes
                        - taskTypeCodes
                        - skills
                        - languages
                        - capacity
                        - toolGrants
                        - eligibleActionCodes
                        - active
                        - lastModifiedAt
                      properties:
                        workerId:
                          type: integer
                        workerCode:
                          type: string
                        displayName:
                          type: string
                        adapterCode:
                          type: string
                        contractVersion:
                          type: string
                        queueCodes:
                          type: array
                          items:
                            type: string
                        taskTypeCodes:
                          type: array
                          items:
                            type: string
                        skills:
                          type: array
                          items:
                            type: string
                        languages:
                          type: array
                          items:
                            type: string
                        capacity:
                          type: integer
                        toolGrants:
                          type: array
                          items:
                            type: string
                        eligibleActionCodes:
                          type: array
                          items:
                            type: string
                        active:
                          type: boolean
                        lastModifiedAt:
                          type: string
                          format: date-time
                  limit:
                    type: integer
                  offset:
                    type: integer
                  hasMore:
                    type: boolean
              example:
                items:
                  - workerId: 5101
                    workerCode: COLLECTIONS_VOICE_PRIMARY
                    displayName: Collections voice agent
                    adapterCode: OUTBOUND_VOICE_V1
                    contractVersion: "1.0"
                    queueCodes:
                      - COLLECTIONS
                    taskTypeCodes:
                      - COLLECTIONS_OUTREACH
                    skills:
                      - COLLECTIONS
                      - VOICE
                    languages:
                      - en
                    capacity: 20
                    toolGrants:
                      - CHECK_CONTACT_ELIGIBILITY
                      - SUBMIT_VOICE_DISPOSITION
                    eligibleActionCodes:
                      - AR_002_CREATE_PROMISE_TO_PAY
                      - AR_007_PREPARE_BORROWER_AUTHORIZED_PAYMENT
                    active: true
                    lastModifiedAt: 2026-07-25T18:30:00Z
                limit: 50
                offset: 0
                hasMore: false
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
    post:
      tags:
        - Workforce
      operationId: createAiWorker
      summary: Register an AI worker
      description: Registers an AI worker against a code-owned adapter contract and validates its eligibility and grants.
      x-permission: CREATE_SERVICING_WORKER
      x-idempotent: true
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: Idempotency-Key
          in: header
          required: false
          description: Optional replay key for this logical mutation. Omission creates a fresh server-owned key for this attempt;
            blank, repeated, or longer-than-50-character values are rejected.
          schema:
            type: string
            minLength: 1
            maxLength: 50
      responses:
        "201":
          description: Created.
          content:
            application/json:
              schema:
                type: object
                required:
                  - workerId
                  - workerCode
                  - active
                  - resourceId
                properties:
                  workerId:
                    type: integer
                  workerCode:
                    type: string
                  active:
                    type: boolean
                  resourceId:
                    type: integer
              example:
                workerId: 5101
                workerCode: COLLECTIONS_VOICE_PRIMARY
                active: true
                resourceId: 5101
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
        "409":
          $ref: "#/components/responses/Servicing409Error"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - workerCode
                - displayName
                - adapterCode
                - contractVersion
                - queueCodes
                - taskTypeCodes
                - skills
                - languages
                - capacity
                - factGroupGrants
                - toolGrants
                - eligibleActionCodes
                - active
              properties:
                workerCode:
                  type: string
                displayName:
                  type: string
                adapterCode:
                  type: string
                contractVersion:
                  type: string
                credentialRef:
                  type: string
                readinessEvidenceRef:
                  type: string
                queueCodes:
                  type: array
                  items:
                    type: string
                taskTypeCodes:
                  type: array
                  items:
                    type: string
                skills:
                  type: array
                  items:
                    type: string
                languages:
                  type: array
                  items:
                    type: string
                capacity:
                  type: integer
                factGroupGrants:
                  type: array
                  items:
                    type: string
                toolGrants:
                  type: array
                  items:
                    type: string
                eligibleActionCodes:
                  type: array
                  items:
                    type: string
                active:
                  type: boolean
              example:
                workerCode: COLLECTIONS_VOICE_PRIMARY
                displayName: Collections voice agent
                adapterCode: OUTBOUND_VOICE_V1
                contractVersion: "1.0"
                credentialRef: voice-agent-client
                readinessEvidenceRef: eval-2026-07-24
                queueCodes:
                  - COLLECTIONS
                taskTypeCodes:
                  - COLLECTIONS_OUTREACH
                skills:
                  - COLLECTIONS
                  - VOICE
                languages:
                  - en
                capacity: 20
                factGroupGrants:
                  - LOAN
                  - OVERDUE
                  - PAYMENT
                  - PAYMENT_INSTRUMENT
                  - CONTACT
                  - RESTRICTION
                toolGrants:
                  - CHECK_CONTACT_ELIGIBILITY
                  - SUBMIT_VOICE_DISPOSITION
                eligibleActionCodes:
                  - AR_002_CREATE_PROMISE_TO_PAY
                  - AR_007_PREPARE_BORROWER_AUTHORIZED_PAYMENT
                active: true
            example:
              workerCode: COLLECTIONS_VOICE_PRIMARY
              displayName: Collections voice agent
              adapterCode: OUTBOUND_VOICE_V1
              contractVersion: "1.0"
              credentialRef: voice-agent-client
              readinessEvidenceRef: eval-2026-07-24
              queueCodes:
                - COLLECTIONS
              taskTypeCodes:
                - COLLECTIONS_OUTREACH
              skills:
                - COLLECTIONS
                - VOICE
              languages:
                - en
              capacity: 20
              factGroupGrants:
                - LOAN
                - OVERDUE
                - PAYMENT
                - PAYMENT_INSTRUMENT
                - CONTACT
                - RESTRICTION
              toolGrants:
                - CHECK_CONTACT_ELIGIBILITY
                - SUBMIT_VOICE_DISPOSITION
              eligibleActionCodes:
                - AR_002_CREATE_PROMISE_TO_PAY
                - AR_007_PREPARE_BORROWER_AUTHORIZED_PAYMENT
              active: true
  /v1/servicing/workers/{workerId}:
    get:
      tags:
        - Workforce
      operationId: getAiWorker
      summary: Retrieve an AI worker registration
      description: Returns one safe AI registration without resolving credential references or adapter deployment configuration.
      x-permission: READ_SERVICING_WORKER
      x-idempotent: false
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: workerId
          in: path
          required: true
          description: Positive numeric worker identifier.
          schema:
            type: integer
            format: int64
            minimum: 1
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - workerId
                  - workerCode
                  - displayName
                  - adapterCode
                  - contractVersion
                  - queueCodes
                  - taskTypeCodes
                  - skills
                  - languages
                  - capacity
                  - toolGrants
                  - eligibleActionCodes
                  - active
                  - lastModifiedAt
                properties:
                  workerId:
                    type: integer
                  workerCode:
                    type: string
                  displayName:
                    type: string
                  adapterCode:
                    type: string
                  contractVersion:
                    type: string
                  queueCodes:
                    type: array
                    items:
                      type: string
                  taskTypeCodes:
                    type: array
                    items:
                      type: string
                  skills:
                    type: array
                    items:
                      type: string
                  languages:
                    type: array
                    items:
                      type: string
                  capacity:
                    type: integer
                  toolGrants:
                    type: array
                    items:
                      type: string
                  eligibleActionCodes:
                    type: array
                    items:
                      type: string
                  active:
                    type: boolean
                  lastModifiedAt:
                    type: string
                    format: date-time
              example:
                workerId: 5101
                workerCode: COLLECTIONS_VOICE_PRIMARY
                displayName: Collections voice agent
                adapterCode: OUTBOUND_VOICE_V1
                contractVersion: "1.0"
                queueCodes:
                  - COLLECTIONS
                taskTypeCodes:
                  - COLLECTIONS_OUTREACH
                skills:
                  - COLLECTIONS
                  - VOICE
                languages:
                  - en
                capacity: 20
                toolGrants:
                  - CHECK_CONTACT_ELIGIBILITY
                  - SUBMIT_VOICE_DISPOSITION
                eligibleActionCodes:
                  - AR_002_CREATE_PROMISE_TO_PAY
                  - AR_007_PREPARE_BORROWER_AUTHORIZED_PAYMENT
                active: true
                lastModifiedAt: 2026-07-25T18:30:00Z
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
    put:
      tags:
        - Workforce
      operationId: replaceAiWorker
      summary: Replace an AI worker registration
      description: Replaces every mutable registration field and revalidates the full contract before activation.
      x-permission: UPDATE_SERVICING_WORKER
      x-idempotent: true
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: workerId
          in: path
          required: true
          description: Positive numeric worker identifier.
          schema:
            type: integer
            format: int64
            minimum: 1
        - name: Idempotency-Key
          in: header
          required: false
          description: Optional replay key for this logical mutation. Omission creates a fresh server-owned key for this attempt;
            blank, repeated, or longer-than-50-character values are rejected.
          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
                      - registrationUpdated
                    properties:
                      active:
                        type: boolean
                      registrationUpdated:
                        type: boolean
              example:
                resourceId: 5101
                changes:
                  active: true
                  registrationUpdated: true
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
        "409":
          $ref: "#/components/responses/Servicing409Error"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - displayName
                - adapterCode
                - contractVersion
                - credentialRef
                - readinessEvidenceRef
                - queueCodes
                - taskTypeCodes
                - skills
                - languages
                - capacity
                - factGroupGrants
                - toolGrants
                - eligibleActionCodes
                - active
              properties:
                workerCode:
                  type: string
                displayName:
                  type: string
                adapterCode:
                  type: string
                contractVersion:
                  type: string
                credentialRef:
                  type: string
                readinessEvidenceRef:
                  type: string
                queueCodes:
                  type: array
                  items:
                    type: string
                taskTypeCodes:
                  type: array
                  items:
                    type: string
                skills:
                  type: array
                  items:
                    type: string
                languages:
                  type: array
                  items:
                    type: string
                capacity:
                  type: integer
                factGroupGrants:
                  type: array
                  items:
                    type: string
                toolGrants:
                  type: array
                  items:
                    type: string
                eligibleActionCodes:
                  type: array
                  items:
                    type: string
                active:
                  type: boolean
              example:
                workerCode: COLLECTIONS_VOICE_PRIMARY
                displayName: Collections voice agent v2
                adapterCode: OUTBOUND_VOICE_V1
                contractVersion: "1.0"
                credentialRef: voice-agent-client
                readinessEvidenceRef: eval-2026-07-24
                queueCodes:
                  - COLLECTIONS
                taskTypeCodes:
                  - COLLECTIONS_OUTREACH
                skills:
                  - COLLECTIONS
                  - VOICE
                languages:
                  - en
                capacity: 20
                factGroupGrants:
                  - LOAN
                  - OVERDUE
                  - PAYMENT
                  - PAYMENT_INSTRUMENT
                  - CONTACT
                  - RESTRICTION
                toolGrants:
                  - CHECK_CONTACT_ELIGIBILITY
                  - SUBMIT_VOICE_DISPOSITION
                eligibleActionCodes:
                  - AR_002_CREATE_PROMISE_TO_PAY
                  - AR_007_PREPARE_BORROWER_AUTHORIZED_PAYMENT
                active: true
            example:
              workerCode: COLLECTIONS_VOICE_PRIMARY
              displayName: Collections voice agent v2
              adapterCode: OUTBOUND_VOICE_V1
              contractVersion: "1.0"
              credentialRef: voice-agent-client
              readinessEvidenceRef: eval-2026-07-24
              queueCodes:
                - COLLECTIONS
              taskTypeCodes:
                - COLLECTIONS_OUTREACH
              skills:
                - COLLECTIONS
                - VOICE
              languages:
                - en
              capacity: 20
              factGroupGrants:
                - LOAN
                - OVERDUE
                - PAYMENT
                - PAYMENT_INSTRUMENT
                - CONTACT
                - RESTRICTION
              toolGrants:
                - CHECK_CONTACT_ELIGIBILITY
                - SUBMIT_VOICE_DISPOSITION
              eligibleActionCodes:
                - AR_002_CREATE_PROMISE_TO_PAY
                - AR_007_PREPARE_BORROWER_AUTHORIZED_PAYMENT
              active: true
  /v1/servicing/cases/{caseId}/escalation-targets:
    get:
      tags:
        - Cases
      operationId: getCaseEscalationTargets
      summary: List case escalation targets
      description: "Returns escalation destinations under the escalate authority: eligible queues plus under-capacity
        escalation people, supervisors, and compliance reviewers. The capacity key is omitted for uncapped workers."
      x-permission: ESCALATE_SERVICING_CASE
      x-idempotent: false
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: caseId
          in: path
          required: true
          description: Positive numeric case identifier.
          schema:
            type: integer
            format: int64
            minimum: 1
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - caseId
                  - queues
                  - people
                  - supervisors
                  - complianceReviewers
                properties:
                  caseId:
                    type: integer
                    description: Stable opaque servicing case identifier.
                  queues:
                    type: array
                    items:
                      type: object
                      required:
                        - queueCode
                        - displayName
                      properties:
                        queueCode:
                          type: string
                        displayName:
                          type: string
                  people:
                    type: array
                    items:
                      type: object
                      required:
                        - workerId
                        - displayName
                        - activeTaskCount
                        - capacity
                      properties:
                        workerId:
                          type: integer
                        displayName:
                          type: string
                        activeTaskCount:
                          type: integer
                        capacity:
                          type: integer
                  supervisors:
                    type: array
                    items:
                      type: object
                      required:
                        - workerId
                        - displayName
                        - activeTaskCount
                        - capacity
                      properties:
                        workerId:
                          type: integer
                        displayName:
                          type: string
                        activeTaskCount:
                          type: integer
                        capacity:
                          type: integer
                  complianceReviewers:
                    type: array
                    items:
                      type: object
                      required:
                        - workerId
                        - displayName
                        - activeTaskCount
                      properties:
                        workerId:
                          type: integer
                        displayName:
                          type: string
                        activeTaskCount:
                          type: integer
              example:
                caseId: 1001
                queues:
                  - queueCode: ESCALATION
                    displayName: Escalation
                people:
                  - workerId: 4103
                    displayName: Evan Escalation
                    activeTaskCount: 3
                    capacity: 6
                supervisors:
                  - workerId: 4103
                    displayName: Evan Escalation
                    activeTaskCount: 3
                    capacity: 6
                complianceReviewers:
                  - workerId: 4104
                    displayName: Cora Compliance
                    activeTaskCount: 1
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
  /v1/servicing/cases/{caseId}/reopen:
    post:
      tags:
        - Cases
      operationId: reopenCase
      summary: Reopen a case
      description: Reopens a closed case under its configured routing and workflow rules without caller-selected assignment.
      x-permission: REOPEN_SERVICING_CASE
      x-idempotent: true
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: caseId
          in: path
          required: true
          description: Positive numeric case identifier.
          schema:
            type: integer
            format: int64
            minimum: 1
        - name: Idempotency-Key
          in: header
          required: false
          description: Optional replay key for this logical mutation. Omission creates a fresh server-owned key for this attempt;
            blank, repeated, or longer-than-50-character values are rejected.
          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:
                      - status
                      - priority
                    properties:
                      status:
                        type: string
                        description: Current normalized lifecycle state.
                      priority:
                        type: string
              example:
                resourceId: 1001
                changes:
                  status: OPEN
                  priority: HIGH
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
        "409":
          $ref: "#/components/responses/Servicing409Error"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - reason
              properties:
                reason:
                  type: string
                priority:
                  type: string
                ownerQueueCode:
                  type: string
              example:
                reason: A new material customer signal was received.
                priority: HIGH
                ownerQueueCode: COLLECTIONS
            example:
              reason: A new material customer signal was received.
              priority: HIGH
              ownerQueueCode: COLLECTIONS
  /v1/servicing/cases/{caseId}/relationships:
    post:
      tags:
        - Cases
      operationId: createCaseRelationship
      summary: Create a case relationship
      description: Creates or idempotently returns a reversible RELATED or POSSIBLE_DUPLICATE relationship without merging
        case history.
      x-permission: UPDATE_SERVICING_CASE
      x-idempotent: true
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: caseId
          in: path
          required: true
          description: Positive numeric case identifier.
          schema:
            type: integer
            format: int64
            minimum: 1
        - name: Idempotency-Key
          in: header
          required: false
          description: Optional replay key for this logical mutation. Omission creates a fresh server-owned key for this attempt;
            blank, repeated, or longer-than-50-character values are rejected.
          schema:
            type: string
            minLength: 1
            maxLength: 50
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - relationshipId
                  - leftCaseId
                  - rightCaseId
                  - relationshipType
                  - status
                  - resourceId
                  - changes
                properties:
                  relationshipId:
                    type: integer
                  leftCaseId:
                    type: integer
                  rightCaseId:
                    type: integer
                  relationshipType:
                    type: string
                  status:
                    type: string
                    description: Current normalized lifecycle state.
                  resourceId:
                    type: integer
                  changes:
                    type: object
                    required:
                      - relationshipStatus
                    properties:
                      relationshipStatus:
                        type: string
              example:
                relationshipId: 501
                leftCaseId: 1001
                rightCaseId: 1002
                relationshipType: POSSIBLE_DUPLICATE
                status: ACTIVE
                resourceId: 501
                changes:
                  relationshipStatus: ACTIVE
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
        "409":
          $ref: "#/components/responses/Servicing409Error"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - otherCaseId
                - relationshipType
                - reason
              properties:
                otherCaseId:
                  type: integer
                relationshipType:
                  type: string
                reason:
                  type: string
              example:
                otherCaseId: 1002
                relationshipType: POSSIBLE_DUPLICATE
                reason: Both cases originate from the same customer email thread.
            example:
              otherCaseId: 1002
              relationshipType: POSSIBLE_DUPLICATE
              reason: Both cases originate from the same customer email thread.
  /v1/servicing/cases/{caseId}/relationships/{relationshipId}/confirm:
    post:
      tags:
        - Cases
      operationId: confirmCaseRelationship
      summary: Confirm a case relationship
      description: Confirms a relationship and, for a possible duplicate, marks only the selected duplicate while preserving
        both histories.
      x-permission: UPDATE_SERVICING_CASE
      x-idempotent: true
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: caseId
          in: path
          required: true
          description: Positive numeric case identifier.
          schema:
            type: integer
            format: int64
            minimum: 1
        - name: relationshipId
          in: path
          required: true
          description: Positive numeric relationship identifier.
          schema:
            type: integer
            format: int64
            minimum: 1
        - name: Idempotency-Key
          in: header
          required: false
          description: Optional replay key for this logical mutation. Omission creates a fresh server-owned key for this attempt;
            blank, repeated, or longer-than-50-character values are rejected.
          schema:
            type: string
            minLength: 1
            maxLength: 50
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - relationshipId
                  - status
                  - resourceId
                  - changes
                properties:
                  relationshipId:
                    type: integer
                  status:
                    type: string
                    description: Current normalized lifecycle state.
                  resourceId:
                    type: integer
                  changes:
                    type: object
                    required:
                      - relationshipStatus
                      - duplicateCaseId
                      - primaryCaseId
                    properties:
                      relationshipStatus:
                        type: string
                      duplicateCaseId:
                        type: integer
                      primaryCaseId:
                        type: integer
              example:
                relationshipId: 501
                status: CONFIRMED
                resourceId: 501
                changes:
                  relationshipStatus: CONFIRMED
                  duplicateCaseId: 1002
                  primaryCaseId: 1001
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
        "409":
          $ref: "#/components/responses/Servicing409Error"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - reason
              properties:
                reason:
                  type: string
                duplicateCaseId:
                  type: integer
              example:
                reason: The records describe the same matter.
                duplicateCaseId: 1002
            example:
              reason: The records describe the same matter.
              duplicateCaseId: 1002
  /v1/servicing/cases/{caseId}/relationships/{relationshipId}/dismiss:
    post:
      tags:
        - Cases
      operationId: dismissCaseRelationship
      summary: Dismiss a case relationship
      description: Dismisses a proposed relationship and leaves both case aggregates unchanged.
      x-permission: UPDATE_SERVICING_CASE
      x-idempotent: true
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: caseId
          in: path
          required: true
          description: Positive numeric case identifier.
          schema:
            type: integer
            format: int64
            minimum: 1
        - name: relationshipId
          in: path
          required: true
          description: Positive numeric relationship identifier.
          schema:
            type: integer
            format: int64
            minimum: 1
        - name: Idempotency-Key
          in: header
          required: false
          description: Optional replay key for this logical mutation. Omission creates a fresh server-owned key for this attempt;
            blank, repeated, or longer-than-50-character values are rejected.
          schema:
            type: string
            minLength: 1
            maxLength: 50
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - relationshipId
                  - status
                  - resourceId
                  - changes
                properties:
                  relationshipId:
                    type: integer
                  status:
                    type: string
                    description: Current normalized lifecycle state.
                  resourceId:
                    type: integer
                  changes:
                    type: object
                    required:
                      - relationshipStatus
                    properties:
                      relationshipStatus:
                        type: string
              example:
                relationshipId: 501
                status: DISMISSED
                resourceId: 501
                changes:
                  relationshipStatus: DISMISSED
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
        "409":
          $ref: "#/components/responses/Servicing409Error"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - reason
              properties:
                reason:
                  type: string
              example:
                reason: The matters have different source events and requested outcomes.
            example:
              reason: The matters have different source events and requested outcomes.
  /v1/servicing/cases/{caseId}/relationships/{relationshipId}/replace:
    post:
      tags:
        - Cases
      operationId: replaceCaseRelationship
      summary: Replace a case relationship
      description: Marks the old relationship replaced and atomically upserts the corrected relationship.
      x-permission: UPDATE_SERVICING_CASE
      x-idempotent: true
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: caseId
          in: path
          required: true
          description: Positive numeric case identifier.
          schema:
            type: integer
            format: int64
            minimum: 1
        - name: relationshipId
          in: path
          required: true
          description: Positive numeric relationship identifier.
          schema:
            type: integer
            format: int64
            minimum: 1
        - name: Idempotency-Key
          in: header
          required: false
          description: Optional replay key for this logical mutation. Omission creates a fresh server-owned key for this attempt;
            blank, repeated, or longer-than-50-character values are rejected.
          schema:
            type: string
            minLength: 1
            maxLength: 50
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - relationshipId
                  - status
                  - resourceId
                  - changes
                properties:
                  relationshipId:
                    type: integer
                  status:
                    type: string
                    description: Current normalized lifecycle state.
                  resourceId:
                    type: integer
                  changes:
                    type: object
                    required:
                      - relationshipStatus
                      - replacementRelationshipId
                    properties:
                      relationshipStatus:
                        type: string
                      replacementRelationshipId:
                        type: integer
              example:
                relationshipId: 501
                status: REPLACED
                resourceId: 501
                changes:
                  relationshipStatus: REPLACED
                  replacementRelationshipId: 502
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
        "409":
          $ref: "#/components/responses/Servicing409Error"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - otherCaseId
                - relationshipType
                - reason
              properties:
                otherCaseId:
                  type: integer
                relationshipType:
                  type: string
                reason:
                  type: string
              example:
                otherCaseId: 1003
                relationshipType: RELATED
                reason: The source was linked to the wrong related matter.
            example:
              otherCaseId: 1003
              relationshipType: RELATED
              reason: The source was linked to the wrong related matter.
  /v1/servicing/supercases:
    get:
      tags:
        - Supercases
      operationId: listSupercases
      summary: List supercases
      description: Lists bounded structural summaries; detailed subcases are read through the case collection.
      x-permission: MANAGE_SERVICING_SUPERCASE
      x-idempotent: false
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: supercaseType
          in: query
          required: false
          description: Filter by supercase type.
          schema:
            type: string
            enum:
              - GENERIC
              - FEMA
              - REMEDIATION
        - name: status
          in: query
          required: false
          description: Repeat to include multiple states.
          schema:
            type: string
        - name: caseTypeCode
          in: query
          required: false
          description: Filter by shared subcase type.
          schema:
            type: string
        - name: sensitive
          in: query
          required: false
          description: Filter by sensitivity.
          schema:
            type: boolean
        - name: createdFrom
          in: query
          required: false
          description: Inclusive timestamp lower bound.
          schema:
            type: string
            format: date-time
        - name: createdTo
          in: query
          required: false
          description: Exclusive timestamp upper bound.
          schema:
            type: string
            format: date-time
        - name: limit
          in: query
          required: false
          description: Maximum rows to return; defaults to 50.
          schema:
            type: integer
            minimum: 1
            maximum: 200
            default: 50
        - name: offset
          in: query
          required: false
          description: Zero-based row offset; defaults to 0.
          schema:
            type: integer
            minimum: 0
            default: 0
        - name: sort
          in: query
          required: false
          description: Allowlisted sort field for this collection.
          schema:
            type: string
        - name: order
          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:
                  - items
                  - limit
                  - offset
                  - hasMore
                properties:
                  items:
                    type: array
                    items:
                      type: object
                      required:
                        - supercaseId
                        - externalSupercaseRef
                        - supercaseType
                        - displayName
                        - status
                        - subcaseCaseTypeCode
                        - sensitive
                        - subcaseCount
                        - createdAt
                        - lastUpdatedAt
                      properties:
                        supercaseId:
                          type: integer
                        externalSupercaseRef:
                          type: string
                        supercaseType:
                          type: string
                        displayName:
                          type: string
                        status:
                          type: string
                          description: Current normalized lifecycle state.
                        subcaseCaseTypeCode:
                          type: string
                        sensitive:
                          type: boolean
                        subcaseCount:
                          type: integer
                        createdAt:
                          type: string
                          format: date-time
                        lastUpdatedAt:
                          type: string
                          format: date-time
                  limit:
                    type: integer
                  offset:
                    type: integer
                  hasMore:
                    type: boolean
              example:
                items:
                  - supercaseId: 8001
                    externalSupercaseRef: LE-SUPERCASE-8001
                    supercaseType: FEMA
                    displayName: July wildfire assistance
                    status: ACTIVE
                    subcaseCaseTypeCode: HARDSHIP
                    sensitive: false
                    subcaseCount: 12
                    createdAt: 2026-07-24T16:00:00Z
                    lastUpdatedAt: 2026-07-25T18:30:00Z
                limit: 50
                offset: 0
                hasMore: false
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
    post:
      tags:
        - Supercases
      operationId: createSupercase
      summary: Create a supercase
      description: Creates a portfolio-event container with one shared enabled subcase type; it grants no bulk-action bypass.
      x-permission: MANAGE_SERVICING_SUPERCASE
      x-idempotent: true
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: Idempotency-Key
          in: header
          required: false
          description: Optional replay key for this logical mutation. Omission creates a fresh server-owned key for this attempt;
            blank, repeated, or longer-than-50-character values are rejected.
          schema:
            type: string
            minLength: 1
            maxLength: 50
      responses:
        "201":
          description: Created.
          content:
            application/json:
              schema:
                type: object
                required:
                  - supercaseId
                  - externalSupercaseRef
                  - status
                  - resourceId
                properties:
                  supercaseId:
                    type: integer
                  externalSupercaseRef:
                    type: string
                  status:
                    type: string
                    description: Current normalized lifecycle state.
                  resourceId:
                    type: integer
              example:
                supercaseId: 8001
                externalSupercaseRef: LE-SUPERCASE-8001
                status: ACTIVE
                resourceId: 8001
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
        "409":
          $ref: "#/components/responses/Servicing409Error"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - supercaseType
                - displayName
                - subcaseCaseTypeCode
              properties:
                supercaseType:
                  type: string
                displayName:
                  type: string
                subcaseCaseTypeCode:
                  type: string
                createdSignalRef:
                  type: string
                sensitive:
                  type: boolean
              example:
                supercaseType: FEMA
                displayName: July wildfire assistance
                subcaseCaseTypeCode: HARDSHIP
                createdSignalRef: fema-event-2026-07
                sensitive: false
            example:
              supercaseType: FEMA
              displayName: July wildfire assistance
              subcaseCaseTypeCode: HARDSHIP
              createdSignalRef: fema-event-2026-07
              sensitive: false
  /v1/servicing/supercases/{supercaseId}:
    get:
      tags:
        - Supercases
      operationId: getSupercase
      summary: Retrieve a supercase
      description: Returns one bounded supercase summary, status counts, and the canonical filtered subcases link.
      x-permission: MANAGE_SERVICING_SUPERCASE
      x-idempotent: false
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: supercaseId
          in: path
          required: true
          description: Positive numeric supercase identifier.
          schema:
            type: integer
            format: int64
            minimum: 1
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - supercaseId
                  - externalSupercaseRef
                  - supercaseType
                  - displayName
                  - status
                  - subcaseCaseTypeCode
                  - sensitive
                  - subcaseCount
                  - createdAt
                  - lastUpdatedAt
                  - subcaseStatusCounts
                  - subcasesHref
                properties:
                  supercaseId:
                    type: integer
                  externalSupercaseRef:
                    type: string
                  supercaseType:
                    type: string
                  displayName:
                    type: string
                  status:
                    type: string
                    description: Current normalized lifecycle state.
                  subcaseCaseTypeCode:
                    type: string
                  sensitive:
                    type: boolean
                  subcaseCount:
                    type: integer
                  createdAt:
                    type: string
                    format: date-time
                  lastUpdatedAt:
                    type: string
                    format: date-time
                  subcaseStatusCounts:
                    type: object
                    required:
                      - OPEN
                      - CLOSED
                    properties:
                      OPEN:
                        type: integer
                      CLOSED:
                        type: integer
                  subcasesHref:
                    type: string
              example:
                supercaseId: 8001
                externalSupercaseRef: LE-SUPERCASE-8001
                supercaseType: FEMA
                displayName: July wildfire assistance
                status: ACTIVE
                subcaseCaseTypeCode: HARDSHIP
                sensitive: false
                subcaseCount: 12
                createdAt: 2026-07-24T16:00:00Z
                lastUpdatedAt: 2026-07-25T18:30:00Z
                subcaseStatusCounts:
                  OPEN: 10
                  CLOSED: 2
                subcasesHref: /v1/servicing/cases?supercaseId=8001
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
  /v1/servicing/supercases/{supercaseId}/subcases:
    post:
      tags:
        - Supercases
      operationId: createSupercaseSubcase
      summary: Create a supercase subcase
      description: Creates one ordinary customer case and structurally links it to the supercase.
      x-permission: MANAGE_SERVICING_SUPERCASE
      x-idempotent: true
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: supercaseId
          in: path
          required: true
          description: Positive numeric supercase identifier.
          schema:
            type: integer
            format: int64
            minimum: 1
        - name: Idempotency-Key
          in: header
          required: false
          description: Optional replay key for this logical mutation. Omission creates a fresh server-owned key for this attempt;
            blank, repeated, or longer-than-50-character values are rejected.
          schema:
            type: string
            minLength: 1
            maxLength: 50
      responses:
        "201":
          description: Created.
          content:
            application/json:
              schema:
                type: object
                required:
                  - caseId
                  - externalCaseRef
                  - status
                  - deduplicated
                  - resourceId
                properties:
                  caseId:
                    type: integer
                    description: Stable opaque servicing case identifier.
                  externalCaseRef:
                    type: string
                  status:
                    type: string
                    description: Current normalized lifecycle state.
                  deduplicated:
                    type: boolean
                  resourceId:
                    type: integer
              example:
                caseId: 1001
                externalCaseRef: LE-CASE-1001
                status: OPEN
                deduplicated: false
                resourceId: 1001
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
        "409":
          $ref: "#/components/responses/Servicing409Error"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - customerRef
                - reasonCode
                - priority
              properties:
                customerRef:
                  type: string
                reasonCode:
                  type: string
                  description: Configured structured reason code.
                priority:
                  type: string
                loanRefs:
                  type: array
                  items:
                    type: string
                ownerQueueCode:
                  type: string
              example:
                customerRef: "123"
                reasonCode: DISASTER_ASSISTANCE
                priority: HIGH
                loanRefs:
                  - "456"
                ownerQueueCode: HARDSHIP
            example:
              customerRef: "123"
              reasonCode: DISASTER_ASSISTANCE
              priority: HIGH
              loanRefs:
                - "456"
              ownerQueueCode: HARDSHIP
  /v1/servicing/me:
    get:
      tags:
        - Workforce
      operationId: getCurrentWorkerContext
      summary: Read my worker context
      description: Returns the authenticated HUMAN worker’s identity, eligibility, presence, live reservation, active
        assignments, and capacity state in one self-scoped read. Capacity, reservation, and per-assignment summary and
        due keys are omitted when absent.
      x-permission: READ_SERVICING_TASK
      x-idempotent: false
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - workerId
                  - displayName
                  - active
                  - capacity
                  - taskTypeCodes
                  - queueCodes
                  - presence
                  - activeReservation
                  - activeAssignments
                  - activeAssignmentCount
                  - atCapacity
                properties:
                  workerId:
                    type: integer
                  displayName:
                    type: string
                  active:
                    type: boolean
                  capacity:
                    type: integer
                  taskTypeCodes:
                    type: array
                    items:
                      type: string
                  queueCodes:
                    type: array
                    items:
                      type: string
                  presence:
                    type: object
                    required:
                      - state
                      - channels
                      - since
                      - setBy
                    properties:
                      state:
                        type: string
                      channels:
                        type: array
                        items:
                          type: string
                      since:
                        type: string
                      setBy:
                        type: string
                  activeReservation:
                    type: object
                    required:
                      - taskId
                      - reservationExpiresAt
                    properties:
                      taskId:
                        type: integer
                      reservationExpiresAt:
                        type: string
                        format: date-time
                  activeAssignments:
                    type: array
                    items:
                      type: object
                      required:
                        - taskId
                        - status
                        - taskTypeCode
                        - queueCode
                        - priority
                        - summary
                        - dueAt
                      properties:
                        taskId:
                          type: integer
                        status:
                          type: string
                          description: Current normalized lifecycle state.
                        taskTypeCode:
                          type: string
                        queueCode:
                          type: string
                        priority:
                          type: string
                        summary:
                          type: string
                        dueAt:
                          type: string
                          format: date-time
                  activeAssignmentCount:
                    type: integer
                  atCapacity:
                    type: boolean
              example:
                workerId: 4101
                displayName: Maria Agent
                active: true
                capacity: 8
                taskTypeCodes:
                  - COLLECTIONS_OUTREACH
                queueCodes:
                  - COLLECTIONS
                presence:
                  state: AVAILABLE
                  channels:
                    - PHONE
                    - GENERAL
                  since: 2026-07-25T18:00:00Z
                  setBy: AGENT_TOGGLE
                activeReservation:
                  taskId: 2001
                  reservationExpiresAt: 2026-07-25T18:40:00Z
                activeAssignments:
                  - taskId: 2002
                    status: IN_PROGRESS
                    taskTypeCode: COLLECTIONS_OUTREACH
                    queueCode: COLLECTIONS
                    priority: HIGH
                    summary: Loan 456 is 22 days past due.
                    dueAt: 2026-07-26T17:00:00Z
                activeAssignmentCount: 1
                atCapacity: false
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
  /v1/servicing/task-types:
    get:
      tags:
        - Tasks
      operationId: listTaskTypes
      summary: List available task types
      description: "Returns the presentation-safe task-type catalog for enabled queues: code, display name, default queue, and
        default priority. AI eligibility and worker-type internals are not exposed."
      x-permission: READ_SERVICING_TASK
      x-idempotent: false
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - items
                properties:
                  items:
                    type: array
                    items:
                      type: object
                      required:
                        - code
                        - displayName
                        - defaultQueueCode
                        - defaultPriority
                      properties:
                        code:
                          type: string
                        displayName:
                          type: string
                        defaultQueueCode:
                          type: string
                        defaultPriority:
                          type: string
              example:
                items:
                  - code: COLLECTIONS_OUTREACH
                    displayName: Collections outreach
                    defaultQueueCode: COLLECTIONS
                    defaultPriority: NORMAL
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
  /v1/servicing/tasks/{taskId}:
    get:
      tags:
        - Tasks
      operationId: getTask
      summary: Retrieve a task
      description: Returns task state, owning case, routing, reservation, the typed work context, caller-specific allowed
        actions, allowed outcomes, configured completion fields, and completion evidence.
      x-permission: READ_SERVICING_TASK
      x-idempotent: false
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: taskId
          in: path
          required: true
          description: Positive numeric task identifier.
          schema:
            type: integer
            format: int64
            minimum: 1
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - taskId
                  - caseId
                  - taskTypeCode
                  - status
                  - priority
                  - queueCode
                  - dueAt
                  - sensitive
                  - workContext
                  - allowedActions
                  - allowedOutcomeCodes
                  - completionFieldDefinitions
                  - completionEvidenceIds
                properties:
                  taskId:
                    type: integer
                  caseId:
                    type: integer
                    description: Stable opaque servicing case identifier.
                  taskTypeCode:
                    type: string
                  status:
                    type: string
                    description: Current normalized lifecycle state.
                  priority:
                    type: string
                  queueCode:
                    type: string
                  dueAt:
                    type: string
                    format: date-time
                  sensitive:
                    type: boolean
                  workContext:
                    type: object
                    required:
                      - kind
                      - resourceId
                      - label
                    properties:
                      kind:
                        type: string
                      resourceId:
                        type: integer
                      label:
                        type: string
                  allowedActions:
                    type: array
                    items:
                      type: string
                  allowedOutcomeCodes:
                    type: array
                    items:
                      type: string
                  completionFieldDefinitions:
                    type: object
                    required:
                      - sections
                    properties:
                      sections:
                        type: array
                        items:
                          type: object
                  completionEvidenceIds:
                    type: array
                    items:
                      type: object
              example:
                taskId: 2001
                caseId: 1001
                taskTypeCode: COLLECTIONS_OUTREACH
                status: AVAILABLE
                priority: HIGH
                queueCode: COLLECTIONS
                dueAt: 2026-07-26T17:00:00Z
                sensitive: false
                workContext:
                  kind: CASE
                  resourceId: 1001
                  label: Collections case
                allowedActions:
                  - ACCEPT
                  - REASSIGN
                  - CANCEL
                allowedOutcomeCodes:
                  - CUSTOMER_REACHED
                  - NO_ANSWER
                completionFieldDefinitions:
                  sections: []
                completionEvidenceIds: []
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
  /v1/servicing/tasks/{taskId}/reassignment-options:
    get:
      tags:
        - Tasks
      operationId: getTaskReassignmentOptions
      summary: List task reassignment options
      description: "Returns manager-authorized reassignment destinations: eligible queues for the task and under-capacity
        eligible workers in its current queue. Terminal tasks return empty lists, and the reassign command revalidates
        the chosen target. The capacity key is omitted for uncapped workers."
      x-permission: REASSIGN_SERVICING_TASK
      x-idempotent: false
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: taskId
          in: path
          required: true
          description: Positive numeric task identifier.
          schema:
            type: integer
            format: int64
            minimum: 1
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - taskId
                  - queues
                  - workers
                properties:
                  taskId:
                    type: integer
                  queues:
                    type: array
                    items:
                      type: object
                      required:
                        - queueCode
                        - displayName
                      properties:
                        queueCode:
                          type: string
                        displayName:
                          type: string
                  workers:
                    type: array
                    items:
                      type: object
                      required:
                        - workerId
                        - displayName
                        - workerKind
                        - activeTaskCount
                        - capacity
                      properties:
                        workerId:
                          type: integer
                        displayName:
                          type: string
                        workerKind:
                          type: string
                        activeTaskCount:
                          type: integer
                        capacity:
                          type: integer
              example:
                taskId: 2001
                queues:
                  - queueCode: COLLECTIONS
                    displayName: Collections
                  - queueCode: ESCALATION
                    displayName: Escalation
                workers:
                  - workerId: 4101
                    displayName: Maria Agent
                    workerKind: HUMAN
                    activeTaskCount: 2
                    capacity: 8
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
  /v1/servicing/tasks/reserve-next:
    post:
      tags:
        - Tasks
      operationId: reserveNextServicingTask
      summary: Reserve the next eligible task
      description: Atomically selects and temporarily reserves the highest-ranked eligible task for the authenticated worker.
      x-permission: RESERVE_SERVICING_TASK
      x-idempotent: true
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: Idempotency-Key
          in: header
          required: false
          description: Optional replay key for this logical mutation. Omission creates a fresh server-owned key for this attempt;
            blank, repeated, or longer-than-50-character values are rejected.
          schema:
            type: string
            minLength: 1
            maxLength: 50
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - taskId
                  - reservationExpiresAt
                properties:
                  taskId:
                    type: integer
                  reservationExpiresAt:
                    type: string
                    format: date-time
              example:
                taskId: 2001
                reservationExpiresAt: 2026-07-25T18:40:00Z
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
        "409":
          $ref: "#/components/responses/Servicing409Error"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - queueCode
              properties:
                queueCode:
                  type: string
                taskTypeCodes:
                  type: array
                  items:
                    type: string
              example:
                queueCode: COLLECTIONS
                taskTypeCodes:
                  - COLLECTIONS_OUTREACH
            example:
              queueCode: COLLECTIONS
              taskTypeCodes:
                - COLLECTIONS_OUTREACH
  /v1/servicing/interactions/{interactionId}/transcript:
    get:
      tags:
        - Interactions
      operationId: getInteractionTranscript
      summary: Read an interaction transcript
      description: Returns controlled no-store transcript content after ordinary and sensitive authorization and records the access.
      x-permission: READ_SERVICING_INTERACTION&READ_SERVICING_INTERACTION_SENSITIVE
      x-idempotent: false
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: interactionId
          in: path
          required: true
          description: Positive numeric interaction identifier.
          schema:
            type: integer
            format: int64
            minimum: 1
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - interactionId
                  - content
                  - contentType
                  - expiresAt
                properties:
                  interactionId:
                    type: integer
                  content:
                    type: string
                  contentType:
                    type: string
                  expiresAt:
                    type: string
                    format: date-time
              example:
                interactionId: 3001
                content: Redacted example transcript.
                contentType: text/plain
                expiresAt: 2026-07-25T18:35:00Z
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
  /v1/servicing/interactions/{interactionId}/recording:
    get:
      tags:
        - Interactions
      operationId: getInteractionRecording
      summary: Read an interaction recording
      description: Returns or streams controlled no-store recording content after sensitive authorization and access audit.
      x-permission: READ_SERVICING_INTERACTION&READ_SERVICING_INTERACTION_SENSITIVE
      x-idempotent: false
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: interactionId
          in: path
          required: true
          description: Positive numeric interaction identifier.
          schema:
            type: integer
            format: int64
            minimum: 1
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - interactionId
                  - downloadUrl
                  - expiresAt
                  - contentType
                properties:
                  interactionId:
                    type: integer
                  downloadUrl:
                    type: string
                  expiresAt:
                    type: string
                    format: date-time
                  contentType:
                    type: string
              example:
                interactionId: 3001
                downloadUrl: https://content.example/opaque-signed-token
                expiresAt: 2026-07-25T18:35:00Z
                contentType: audio/mpeg
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
  /v1/servicing/calls/outbound:
    post:
      tags:
        - Interactions
      operationId: startHumanOutboundCall
      summary: Start a human outbound call
      description: "Creates the interaction evidence, runs the execution-time compliance gate immediately before dial, and
        dials through the configured telephony gateway only when the decision allows. The result is always 201 with
        persisted evidence: status is DIALING, BLOCKED, or FAILED, and failureCode is present unless the call is
        dialing. Collections calls must name the case-linked loan, and the contact point must be a verified eligible
        phone."
      x-permission: SEND_SERVICING_INTERACTION
      x-idempotent: true
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: Idempotency-Key
          in: header
          required: false
          description: Optional replay key for this logical mutation. Omission creates a fresh server-owned key for this attempt;
            blank, repeated, or longer-than-50-character values are rejected.
          schema:
            type: string
            minLength: 1
            maxLength: 50
      responses:
        "201":
          description: Created.
          content:
            application/json:
              schema:
                type: object
                required:
                  - callId
                  - interactionId
                  - contactAttemptId
                  - decisionId
                  - status
                  - gatewayCode
                  - dialAuthorized
                  - resourceId
                properties:
                  callId:
                    type: integer
                  interactionId:
                    type: integer
                  contactAttemptId:
                    type: integer
                  decisionId:
                    type: integer
                  status:
                    type: string
                    description: Current normalized lifecycle state.
                  gatewayCode:
                    type: string
                  dialAuthorized:
                    type: boolean
                  resourceId:
                    type: integer
              example:
                callId: 7001
                interactionId: 3003
                contactAttemptId: 9401
                decisionId: 6117
                status: DIALING
                gatewayCode: VOICE_GATEWAY_PRIMARY
                dialAuthorized: true
                resourceId: 7001
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
        "409":
          $ref: "#/components/responses/Servicing409Error"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - caseId
                - customerRef
                - contactPointRef
                - reasonCode
              properties:
                caseId:
                  type: integer
                  description: Stable opaque servicing case identifier.
                customerRef:
                  type: string
                loanRef:
                  type: string
                contactPointRef:
                  type: string
                reasonCode:
                  type: string
                  description: Configured structured reason code.
                recordingRequested:
                  type: boolean
              example:
                caseId: 1001
                customerRef: "123"
                loanRef: "456"
                contactPointRef: phone-1
                reasonCode: PAYMENT_FAILURE
                recordingRequested: false
            example:
              caseId: 1001
              customerRef: "123"
              loanRef: "456"
              contactPointRef: phone-1
              reasonCode: PAYMENT_FAILURE
              recordingRequested: false
  /v1/servicing/customers/{customerRef}/documents:
    get:
      tags:
        - Case documents
      operationId: listCustomerCaseDocuments
      summary: List customer servicing documents
      description: Lists accepted servicing-owned documents linked to the customer.
      x-permission: READ_SERVICING_DOCUMENT
      x-idempotent: false
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: customerRef
          in: path
          required: true
          description: Stable opaque customerRef identifier.
          schema:
            type: string
        - name: documentType
          in: query
          required: false
          description: Exact document type.
          schema:
            type: string
        - name: origin
          in: query
          required: false
          description: Exact intake origin.
          schema:
            type: string
        - name: sensitive
          in: query
          required: false
          description: Filter by sensitivity.
          schema:
            type: boolean
        - name: createdFrom
          in: query
          required: false
          description: Inclusive timestamp lower bound.
          schema:
            type: string
            format: date-time
        - name: createdTo
          in: query
          required: false
          description: Exclusive timestamp upper bound.
          schema:
            type: string
            format: date-time
        - name: limit
          in: query
          required: false
          description: Maximum rows to return; defaults to 50.
          schema:
            type: integer
            minimum: 1
            maximum: 200
            default: 50
        - name: offset
          in: query
          required: false
          description: Zero-based row offset; defaults to 0.
          schema:
            type: integer
            minimum: 0
            default: 0
        - name: sort
          in: query
          required: false
          description: Allowlisted sort field for this collection.
          schema:
            type: string
        - name: order
          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:
                  - items
                  - limit
                  - offset
                  - hasMore
                properties:
                  items:
                    type: array
                    items:
                      type: object
                      required:
                        - documentId
                        - title
                        - documentType
                        - origin
                        - scanStatus
                        - reviewStatus
                        - sensitive
                        - links
                        - createdAt
                      properties:
                        documentId:
                          type: integer
                        title:
                          type: string
                        documentType:
                          type: string
                        origin:
                          type: string
                        scanStatus:
                          type: string
                        reviewStatus:
                          type: string
                        sensitive:
                          type: boolean
                        links:
                          type: array
                          items:
                            type: object
                            required:
                              - targetType
                              - targetRef
                            properties:
                              targetType:
                                type: string
                              targetRef:
                                type: string
                        createdAt:
                          type: string
                          format: date-time
                  limit:
                    type: integer
                  offset:
                    type: integer
                  hasMore:
                    type: boolean
              example:
                items:
                  - documentId: 7001
                    title: Bankruptcy notice filed June 14
                    documentType: BANKRUPTCY_NOTICE
                    origin: BORROWER_UPLOAD
                    scanStatus: CLEAN
                    reviewStatus: ACCEPTED
                    sensitive: true
                    links:
                      - targetType: CASE
                        targetRef: "1001"
                      - targetType: CUSTOMER
                        targetRef: "123"
                      - targetType: LOAN
                        targetRef: "456"
                    createdAt: 2026-07-25T18:30:00Z
                limit: 50
                offset: 0
                hasMore: false
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
  /v1/servicing/loans/{loanRef}/documents:
    get:
      tags:
        - Case documents
      operationId: listLoanCaseDocuments
      summary: List loan servicing documents
      description: Lists accepted servicing-owned documents explicitly linked to the selected loan.
      x-permission: READ_SERVICING_DOCUMENT
      x-idempotent: false
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: loanRef
          in: path
          required: true
          description: Stable opaque loanRef identifier.
          schema:
            type: string
        - name: documentType
          in: query
          required: false
          description: Exact document type.
          schema:
            type: string
        - name: origin
          in: query
          required: false
          description: Exact intake origin.
          schema:
            type: string
        - name: sensitive
          in: query
          required: false
          description: Filter by sensitivity.
          schema:
            type: boolean
        - name: createdFrom
          in: query
          required: false
          description: Inclusive timestamp lower bound.
          schema:
            type: string
            format: date-time
        - name: createdTo
          in: query
          required: false
          description: Exclusive timestamp upper bound.
          schema:
            type: string
            format: date-time
        - name: limit
          in: query
          required: false
          description: Maximum rows to return; defaults to 50.
          schema:
            type: integer
            minimum: 1
            maximum: 200
            default: 50
        - name: offset
          in: query
          required: false
          description: Zero-based row offset; defaults to 0.
          schema:
            type: integer
            minimum: 0
            default: 0
        - name: sort
          in: query
          required: false
          description: Allowlisted sort field for this collection.
          schema:
            type: string
        - name: order
          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:
                  - items
                  - limit
                  - offset
                  - hasMore
                properties:
                  items:
                    type: array
                    items:
                      type: object
                      required:
                        - documentId
                        - title
                        - documentType
                        - origin
                        - scanStatus
                        - reviewStatus
                        - sensitive
                        - links
                        - createdAt
                      properties:
                        documentId:
                          type: integer
                        title:
                          type: string
                        documentType:
                          type: string
                        origin:
                          type: string
                        scanStatus:
                          type: string
                        reviewStatus:
                          type: string
                        sensitive:
                          type: boolean
                        links:
                          type: array
                          items:
                            type: object
                            required:
                              - targetType
                              - targetRef
                            properties:
                              targetType:
                                type: string
                              targetRef:
                                type: string
                        createdAt:
                          type: string
                          format: date-time
                  limit:
                    type: integer
                  offset:
                    type: integer
                  hasMore:
                    type: boolean
              example:
                items:
                  - documentId: 7001
                    title: Bankruptcy notice filed June 14
                    documentType: BANKRUPTCY_NOTICE
                    origin: BORROWER_UPLOAD
                    scanStatus: CLEAN
                    reviewStatus: ACCEPTED
                    sensitive: true
                    links:
                      - targetType: CASE
                        targetRef: "1001"
                      - targetType: CUSTOMER
                        targetRef: "123"
                      - targetType: LOAN
                        targetRef: "456"
                    createdAt: 2026-07-25T18:30:00Z
                limit: 50
                offset: 0
                hasMore: false
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
  /v1/servicing/documents/{documentId}/content:
    get:
      tags:
        - Case documents
      operationId: getCaseDocumentContent
      summary: Create a controlled document download
      description: Returns a no-store short-lived content envelope only for scan-clean authorized content and audits access.
      x-permission: READ_SERVICING_DOCUMENT
      x-idempotent: false
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: documentId
          in: path
          required: true
          description: Positive numeric document identifier.
          schema:
            type: integer
            format: int64
            minimum: 1
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - downloadUrl
                  - expiresAt
                  - fileName
                  - contentType
                  - checksumSha256
                properties:
                  downloadUrl:
                    type: string
                  expiresAt:
                    type: string
                    format: date-time
                  fileName:
                    type: string
                  contentType:
                    type: string
                  checksumSha256:
                    type: string
              example:
                downloadUrl: https://content.example/opaque-signed-token
                expiresAt: 2026-07-25T18:35:00Z
                fileName: bankruptcy-notice.pdf
                contentType: application/pdf
                checksumSha256: 2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
  /v1/servicing/documents/{documentId}/archive:
    post:
      tags:
        - Case documents
      operationId: archiveCaseDocument
      summary: Archive a case document
      description: Archives a document under retention and hold rules while preserving its audit identity.
      x-permission: ARCHIVE_SERVICING_DOCUMENT
      x-idempotent: true
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: documentId
          in: path
          required: true
          description: Positive numeric document identifier.
          schema:
            type: integer
            format: int64
            minimum: 1
        - name: Idempotency-Key
          in: header
          required: false
          description: Optional replay key for this logical mutation. Omission creates a fresh server-owned key for this attempt;
            blank, repeated, or longer-than-50-character values are rejected.
          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:
                      - status
                    properties:
                      status:
                        type: string
                        description: Current normalized lifecycle state.
              example:
                resourceId: 7001
                changes:
                  status: ARCHIVED
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
        "409":
          $ref: "#/components/responses/Servicing409Error"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - reason
              properties:
                reason:
                  type: string
              example:
                reason: Superseded by an accepted corrected filing.
            example:
              reason: Superseded by an accepted corrected filing.
  /v1/servicing/documents/{documentId}/loan-links:
    put:
      tags:
        - Case documents
      operationId: replaceCaseDocumentLoanLinks
      summary: Replace document loan links
      description: Atomically replaces optional selected-loan links while retaining required case/customer links and
        historical retention scope.
      x-permission: UPDATE_SERVICING_DOCUMENT
      x-idempotent: true
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: documentId
          in: path
          required: true
          description: Positive numeric document identifier.
          schema:
            type: integer
            format: int64
            minimum: 1
        - name: Idempotency-Key
          in: header
          required: false
          description: Optional replay key for this logical mutation. Omission creates a fresh server-owned key for this attempt;
            blank, repeated, or longer-than-50-character values are rejected.
          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:
                      - loanRefs
                    properties:
                      loanRefs:
                        type: array
                        items:
                          type: string
              example:
                resourceId: 7001
                changes:
                  loanRefs:
                    - "456"
                    - "457"
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
        "409":
          $ref: "#/components/responses/Servicing409Error"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - loanRefs
                - reason
              properties:
                loanRefs:
                  type: array
                  items:
                    type: string
                reason:
                  type: string
              example:
                loanRefs:
                  - "456"
                  - "457"
                reason: Reviewer confirmed both loans are covered by the filing.
            example:
              loanRefs:
                - "456"
                - "457"
              reason: Reviewer confirmed both loans are covered by the filing.
  /v1/servicing/cases/{caseId}/notes:
    post:
      tags:
        - Case notes
      operationId: createCaseNote
      summary: Create a case note
      description: Creates a revisioned operational note with derived case/customer links and optional selected-loan links.
      x-permission: CREATE_SERVICING_NOTE
      x-idempotent: true
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: caseId
          in: path
          required: true
          description: Positive numeric case identifier.
          schema:
            type: integer
            format: int64
            minimum: 1
        - name: Idempotency-Key
          in: header
          required: false
          description: Optional replay key for this logical mutation. Omission creates a fresh server-owned key for this attempt;
            blank, repeated, or longer-than-50-character values are rejected.
          schema:
            type: string
            minLength: 1
            maxLength: 50
      responses:
        "201":
          description: Created.
          content:
            application/json:
              schema:
                type: object
                required:
                  - noteId
                  - revision
                  - status
                  - links
                  - resourceId
                properties:
                  noteId:
                    type: integer
                  revision:
                    type: integer
                  status:
                    type: string
                    description: Current normalized lifecycle state.
                  links:
                    type: array
                    items:
                      type: object
                      required:
                        - targetType
                        - targetRef
                      properties:
                        targetType:
                          type: string
                        targetRef:
                          type: string
                  resourceId:
                    type: integer
              example:
                noteId: 7201
                revision: 1
                status: ACTIVE
                links:
                  - targetType: CASE
                    targetRef: "1001"
                  - targetType: CUSTOMER
                    targetRef: "123"
                  - targetType: LOAN
                    targetRef: "456"
                resourceId: 7201
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
        "409":
          $ref: "#/components/responses/Servicing409Error"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - body
              properties:
                body:
                  type: string
                loanRefs:
                  type: array
                  items:
                    type: string
                sensitive:
                  type: boolean
                pinned:
                  type: boolean
                flagged:
                  type: boolean
              example:
                body: Customer will provide the missing filing page through secure upload.
                loanRefs:
                  - "456"
                sensitive: true
                pinned: true
                flagged: false
            example:
              body: Customer will provide the missing filing page through secure upload.
              loanRefs:
                - "456"
              sensitive: true
              pinned: true
              flagged: false
    get:
      tags:
        - Case notes
      operationId: listCaseNotes
      summary: List case notes
      description: Lists authorized case-linked note projections using exact status, sensitivity, flag, and time filters.
      x-permission: READ_SERVICING_NOTE
      x-idempotent: false
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: caseId
          in: path
          required: true
          description: Positive numeric case identifier.
          schema:
            type: integer
            format: int64
            minimum: 1
        - name: status
          in: query
          required: false
          description: Exact note lifecycle state.
          schema:
            type: string
        - name: sensitive
          in: query
          required: false
          description: Filter by sensitivity.
          schema:
            type: boolean
        - name: pinned
          in: query
          required: false
          description: Filter by pinned state.
          schema:
            type: boolean
        - name: flagged
          in: query
          required: false
          description: Filter by flagged state.
          schema:
            type: boolean
        - name: createdFrom
          in: query
          required: false
          description: Inclusive timestamp lower bound.
          schema:
            type: string
            format: date-time
        - name: createdTo
          in: query
          required: false
          description: Exclusive timestamp upper bound.
          schema:
            type: string
            format: date-time
        - name: limit
          in: query
          required: false
          description: Maximum rows to return; defaults to 50.
          schema:
            type: integer
            minimum: 1
            maximum: 200
            default: 50
        - name: offset
          in: query
          required: false
          description: Zero-based row offset; defaults to 0.
          schema:
            type: integer
            minimum: 0
            default: 0
        - name: sort
          in: query
          required: false
          description: Allowlisted sort field for this collection.
          schema:
            type: string
        - name: order
          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:
                  - items
                  - limit
                  - offset
                  - hasMore
                properties:
                  items:
                    type: array
                    items:
                      type: object
                      required:
                        - noteId
                        - revision
                        - status
                        - body
                        - sensitive
                        - pinned
                        - flagged
                        - createdByDisplayName
                        - createdByActorType
                        - links
                        - createdAt
                      properties:
                        noteId:
                          type: integer
                        revision:
                          type: integer
                        status:
                          type: string
                          description: Current normalized lifecycle state.
                        body:
                          type: string
                        sensitive:
                          type: boolean
                        pinned:
                          type: boolean
                        flagged:
                          type: boolean
                        createdByDisplayName:
                          type: string
                        createdByActorType:
                          type: string
                        links:
                          type: array
                          items:
                            type: object
                            required:
                              - targetType
                              - targetRef
                            properties:
                              targetType:
                                type: string
                              targetRef:
                                type: string
                        createdAt:
                          type: string
                          format: date-time
                  limit:
                    type: integer
                  offset:
                    type: integer
                  hasMore:
                    type: boolean
              example:
                items:
                  - noteId: 7201
                    revision: 1
                    status: ACTIVE
                    body: Customer will provide the missing filing page through secure upload.
                    sensitive: true
                    pinned: true
                    flagged: false
                    createdByDisplayName: Maria Agent
                    createdByActorType: HUMAN
                    links:
                      - targetType: CASE
                        targetRef: "1001"
                      - targetType: CUSTOMER
                        targetRef: "123"
                      - targetType: LOAN
                        targetRef: "456"
                    createdAt: 2026-07-25T18:30:00Z
                limit: 50
                offset: 0
                hasMore: false
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
  /v1/servicing/customers/{customerRef}/notes:
    get:
      tags:
        - Case notes
      operationId: listCustomerCaseNotes
      summary: List customer servicing notes
      description: Lists servicing-owned notes linked to the customer, with sensitive bodies masked unless separately authorized.
      x-permission: READ_SERVICING_NOTE
      x-idempotent: false
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: customerRef
          in: path
          required: true
          description: Stable opaque customerRef identifier.
          schema:
            type: string
        - name: status
          in: query
          required: false
          description: Exact note lifecycle state.
          schema:
            type: string
        - name: sensitive
          in: query
          required: false
          description: Filter by sensitivity.
          schema:
            type: boolean
        - name: pinned
          in: query
          required: false
          description: Filter by pinned state.
          schema:
            type: boolean
        - name: flagged
          in: query
          required: false
          description: Filter by flagged state.
          schema:
            type: boolean
        - name: createdFrom
          in: query
          required: false
          description: Inclusive timestamp lower bound.
          schema:
            type: string
            format: date-time
        - name: createdTo
          in: query
          required: false
          description: Exclusive timestamp upper bound.
          schema:
            type: string
            format: date-time
        - name: limit
          in: query
          required: false
          description: Maximum rows to return; defaults to 50.
          schema:
            type: integer
            minimum: 1
            maximum: 200
            default: 50
        - name: offset
          in: query
          required: false
          description: Zero-based row offset; defaults to 0.
          schema:
            type: integer
            minimum: 0
            default: 0
        - name: sort
          in: query
          required: false
          description: Allowlisted sort field for this collection.
          schema:
            type: string
        - name: order
          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:
                  - items
                  - limit
                  - offset
                  - hasMore
                properties:
                  items:
                    type: array
                    items:
                      type: object
                      required:
                        - noteId
                        - revision
                        - status
                        - body
                        - sensitive
                        - pinned
                        - flagged
                        - createdByDisplayName
                        - createdByActorType
                        - links
                        - createdAt
                      properties:
                        noteId:
                          type: integer
                        revision:
                          type: integer
                        status:
                          type: string
                          description: Current normalized lifecycle state.
                        body:
                          type: string
                        sensitive:
                          type: boolean
                        pinned:
                          type: boolean
                        flagged:
                          type: boolean
                        createdByDisplayName:
                          type: string
                        createdByActorType:
                          type: string
                        links:
                          type: array
                          items:
                            type: object
                            required:
                              - targetType
                              - targetRef
                            properties:
                              targetType:
                                type: string
                              targetRef:
                                type: string
                        createdAt:
                          type: string
                          format: date-time
                  limit:
                    type: integer
                  offset:
                    type: integer
                  hasMore:
                    type: boolean
              example:
                items:
                  - noteId: 7201
                    revision: 1
                    status: ACTIVE
                    body: Customer will provide the missing filing page through secure upload.
                    sensitive: true
                    pinned: true
                    flagged: false
                    createdByDisplayName: Maria Agent
                    createdByActorType: HUMAN
                    links:
                      - targetType: CASE
                        targetRef: "1001"
                      - targetType: CUSTOMER
                        targetRef: "123"
                      - targetType: LOAN
                        targetRef: "456"
                    createdAt: 2026-07-25T18:30:00Z
                limit: 50
                offset: 0
                hasMore: false
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
  /v1/servicing/loans/{loanRef}/notes:
    get:
      tags:
        - Case notes
      operationId: listLoanCaseNotes
      summary: List loan servicing notes
      description: Lists servicing-owned notes explicitly linked to the selected loan.
      x-permission: READ_SERVICING_NOTE
      x-idempotent: false
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: loanRef
          in: path
          required: true
          description: Stable opaque loanRef identifier.
          schema:
            type: string
        - name: status
          in: query
          required: false
          description: Exact note lifecycle state.
          schema:
            type: string
        - name: sensitive
          in: query
          required: false
          description: Filter by sensitivity.
          schema:
            type: boolean
        - name: pinned
          in: query
          required: false
          description: Filter by pinned state.
          schema:
            type: boolean
        - name: flagged
          in: query
          required: false
          description: Filter by flagged state.
          schema:
            type: boolean
        - name: createdFrom
          in: query
          required: false
          description: Inclusive timestamp lower bound.
          schema:
            type: string
            format: date-time
        - name: createdTo
          in: query
          required: false
          description: Exclusive timestamp upper bound.
          schema:
            type: string
            format: date-time
        - name: limit
          in: query
          required: false
          description: Maximum rows to return; defaults to 50.
          schema:
            type: integer
            minimum: 1
            maximum: 200
            default: 50
        - name: offset
          in: query
          required: false
          description: Zero-based row offset; defaults to 0.
          schema:
            type: integer
            minimum: 0
            default: 0
        - name: sort
          in: query
          required: false
          description: Allowlisted sort field for this collection.
          schema:
            type: string
        - name: order
          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:
                  - items
                  - limit
                  - offset
                  - hasMore
                properties:
                  items:
                    type: array
                    items:
                      type: object
                      required:
                        - noteId
                        - revision
                        - status
                        - body
                        - sensitive
                        - pinned
                        - flagged
                        - createdByDisplayName
                        - createdByActorType
                        - links
                        - createdAt
                      properties:
                        noteId:
                          type: integer
                        revision:
                          type: integer
                        status:
                          type: string
                          description: Current normalized lifecycle state.
                        body:
                          type: string
                        sensitive:
                          type: boolean
                        pinned:
                          type: boolean
                        flagged:
                          type: boolean
                        createdByDisplayName:
                          type: string
                        createdByActorType:
                          type: string
                        links:
                          type: array
                          items:
                            type: object
                            required:
                              - targetType
                              - targetRef
                            properties:
                              targetType:
                                type: string
                              targetRef:
                                type: string
                        createdAt:
                          type: string
                          format: date-time
                  limit:
                    type: integer
                  offset:
                    type: integer
                  hasMore:
                    type: boolean
              example:
                items:
                  - noteId: 7201
                    revision: 1
                    status: ACTIVE
                    body: Customer will provide the missing filing page through secure upload.
                    sensitive: true
                    pinned: true
                    flagged: false
                    createdByDisplayName: Maria Agent
                    createdByActorType: HUMAN
                    links:
                      - targetType: CASE
                        targetRef: "1001"
                      - targetType: CUSTOMER
                        targetRef: "123"
                      - targetType: LOAN
                        targetRef: "456"
                    createdAt: 2026-07-25T18:30:00Z
                limit: 50
                offset: 0
                hasMore: false
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
  /v1/servicing/notes/{noteId}:
    get:
      tags:
        - Case notes
      operationId: getCaseNote
      summary: Retrieve a case note
      description: Returns the current authorized note revision and its stable case/customer/loan links.
      x-permission: READ_SERVICING_NOTE
      x-idempotent: false
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: noteId
          in: path
          required: true
          description: Positive numeric note identifier.
          schema:
            type: integer
            format: int64
            minimum: 1
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - noteId
                  - revision
                  - status
                  - body
                  - sensitive
                  - pinned
                  - flagged
                  - createdByDisplayName
                  - createdByActorType
                  - links
                  - createdAt
                properties:
                  noteId:
                    type: integer
                  revision:
                    type: integer
                  status:
                    type: string
                    description: Current normalized lifecycle state.
                  body:
                    type: string
                  sensitive:
                    type: boolean
                  pinned:
                    type: boolean
                  flagged:
                    type: boolean
                  createdByDisplayName:
                    type: string
                  createdByActorType:
                    type: string
                  links:
                    type: array
                    items:
                      type: object
                      required:
                        - targetType
                        - targetRef
                      properties:
                        targetType:
                          type: string
                        targetRef:
                          type: string
                  createdAt:
                    type: string
                    format: date-time
              example:
                noteId: 7201
                revision: 1
                status: ACTIVE
                body: Customer will provide the missing filing page through secure upload.
                sensitive: true
                pinned: true
                flagged: false
                createdByDisplayName: Maria Agent
                createdByActorType: HUMAN
                links:
                  - targetType: CASE
                    targetRef: "1001"
                  - targetType: CUSTOMER
                    targetRef: "123"
                  - targetType: LOAN
                    targetRef: "456"
                createdAt: 2026-07-25T18:30:00Z
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
    put:
      tags:
        - Case notes
      operationId: reviseCaseNote
      summary: Revise a case note
      description: Appends a new revision while preserving note identity and immutable revision history.
      x-permission: UPDATE_SERVICING_NOTE
      x-idempotent: true
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: noteId
          in: path
          required: true
          description: Positive numeric note identifier.
          schema:
            type: integer
            format: int64
            minimum: 1
        - name: Idempotency-Key
          in: header
          required: false
          description: Optional replay key for this logical mutation. Omission creates a fresh server-owned key for this attempt;
            blank, repeated, or longer-than-50-character values are rejected.
          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:
                      - revision
                      - fieldKeys
                    properties:
                      revision:
                        type: integer
                      fieldKeys:
                        type: array
                        items:
                          type: string
              example:
                resourceId: 7201
                changes:
                  revision: 2
                  fieldKeys:
                    - body
                    - pinned
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
        "409":
          $ref: "#/components/responses/Servicing409Error"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: []
              properties:
                body:
                  type: string
                sensitive:
                  type: boolean
                pinned:
                  type: boolean
                flagged:
                  type: boolean
                changeReason:
                  type: string
              example:
                body: Customer supplied the final filing page through secure upload.
                sensitive: true
                pinned: false
                flagged: false
                changeReason: Recorded verified receipt.
            example:
              body: Customer supplied the final filing page through secure upload.
              sensitive: true
              pinned: false
              flagged: false
              changeReason: Recorded verified receipt.
  /v1/servicing/notes/{noteId}/loan-links:
    put:
      tags:
        - Case notes
      operationId: replaceCaseNoteLoanLinks
      summary: Replace note loan links
      description: Atomically replaces optional selected-loan links without changing note content or revision history.
      x-permission: UPDATE_SERVICING_NOTE
      x-idempotent: true
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: noteId
          in: path
          required: true
          description: Positive numeric note identifier.
          schema:
            type: integer
            format: int64
            minimum: 1
        - name: Idempotency-Key
          in: header
          required: false
          description: Optional replay key for this logical mutation. Omission creates a fresh server-owned key for this attempt;
            blank, repeated, or longer-than-50-character values are rejected.
          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:
                      - loanRefs
                    properties:
                      loanRefs:
                        type: array
                        items:
                          type: string
              example:
                resourceId: 7201
                changes:
                  loanRefs:
                    - "456"
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
        "409":
          $ref: "#/components/responses/Servicing409Error"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - loanRefs
                - reason
              properties:
                loanRefs:
                  type: array
                  items:
                    type: string
                reason:
                  type: string
              example:
                loanRefs:
                  - "456"
                reason: The note applies only to the selected loan.
            example:
              loanRefs:
                - "456"
              reason: The note applies only to the selected loan.
  /v1/servicing/notes/{noteId}/archive:
    post:
      tags:
        - Case notes
      operationId: archiveCaseNote
      summary: Archive a case note
      description: Archives the note under retention rules without deleting its identity or revision history.
      x-permission: ARCHIVE_SERVICING_NOTE
      x-idempotent: true
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: noteId
          in: path
          required: true
          description: Positive numeric note identifier.
          schema:
            type: integer
            format: int64
            minimum: 1
        - name: Idempotency-Key
          in: header
          required: false
          description: Optional replay key for this logical mutation. Omission creates a fresh server-owned key for this attempt;
            blank, repeated, or longer-than-50-character values are rejected.
          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:
                      - status
                    properties:
                      status:
                        type: string
                        description: Current normalized lifecycle state.
              example:
                resourceId: 7201
                changes:
                  status: ARCHIVED
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
        "409":
          $ref: "#/components/responses/Servicing409Error"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - reason
              properties:
                reason:
                  type: string
              example:
                reason: The operational note is no longer current.
            example:
              reason: The operational note is no longer current.
  /v1/servicing/notes/{noteId}/redact:
    post:
      tags:
        - Case notes
      operationId: redactCaseNote
      summary: Redact a case note
      description: Appends a permanent redaction marker revision while retaining audit and link history.
      x-permission: REDACT_SERVICING_NOTE
      x-idempotent: true
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: noteId
          in: path
          required: true
          description: Positive numeric note identifier.
          schema:
            type: integer
            format: int64
            minimum: 1
        - name: Idempotency-Key
          in: header
          required: false
          description: Optional replay key for this logical mutation. Omission creates a fresh server-owned key for this attempt;
            blank, repeated, or longer-than-50-character values are rejected.
          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:
                      - status
                      - revision
                    properties:
                      status:
                        type: string
                        description: Current normalized lifecycle state.
                      revision:
                        type: integer
              example:
                resourceId: 7201
                changes:
                  status: REDACTED
                  revision: 2
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
        "409":
          $ref: "#/components/responses/Servicing409Error"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - reason
              properties:
                reason:
                  type: string
              example:
                reason: Removed content that must not remain visible.
            example:
              reason: Removed content that must not remain visible.
  /v1/servicing/admin/case-types/{caseTypeCode}/field-definitions:
    get:
      tags:
        - Servicing administration
      operationId: getCaseFieldDefinitions
      summary: Retrieve case field definitions
      description: Returns the current presentation and validation schema owned by an existing case type.
      x-permission: ADMIN_SERVICING_CONFIG
      x-idempotent: false
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: caseTypeCode
          in: path
          required: true
          description: Stable opaque caseTypeCode identifier.
          schema:
            type: string
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - caseTypeCode
                  - fieldDefinitions
                properties:
                  caseTypeCode:
                    type: string
                  fieldDefinitions:
                    type: object
                    required:
                      - sections
                    properties:
                      sections:
                        type: array
                        items:
                          type: object
                          required:
                            - key
                            - label
                            - fields
                          properties:
                            key:
                              type: string
                            label:
                              type: string
                            fields:
                              type: array
                              items:
                                type: object
                                required:
                                  - key
                                  - label
                                  - type
                                  - requiredAt
                                properties:
                                  key:
                                    type: string
                                  label:
                                    type: string
                                  type:
                                    type: string
                                  requiredAt:
                                    type: string
                                    format: date-time
              example:
                caseTypeCode: GENERAL_SUPPORT
                fieldDefinitions:
                  sections:
                    - key: service_details
                      label: Service details
                      fields:
                        - key: requested_effective_date
                          label: Requested effective date
                          type: DATE
                          requiredAt: OPTIONAL
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
    put:
      tags:
        - Servicing administration
      operationId: replaceCaseFieldDefinitions
      summary: Replace case field definitions
      description: Replaces the closed configuration object for an existing case type without schema DDL.
      x-permission: ADMIN_SERVICING_CONFIG
      x-idempotent: true
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: caseTypeCode
          in: path
          required: true
          description: Stable opaque caseTypeCode identifier.
          schema:
            type: string
        - name: Idempotency-Key
          in: header
          required: false
          description: Optional replay key for this logical mutation. Omission creates a fresh server-owned key for this attempt;
            blank, repeated, or longer-than-50-character values are rejected.
          schema:
            type: string
            minLength: 1
            maxLength: 50
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - resourceId
                  - caseTypeCode
                  - changes
                properties:
                  resourceId:
                    type: integer
                  caseTypeCode:
                    type: string
                  changes:
                    type: object
                    required:
                      - fieldKeys
                    properties:
                      fieldKeys:
                        type: array
                        items:
                          type: string
              example:
                resourceId: 11
                caseTypeCode: GENERAL_SUPPORT
                changes:
                  fieldKeys:
                    - requested_effective_date
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
        "409":
          $ref: "#/components/responses/Servicing409Error"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - fieldDefinitions
                - reason
              properties:
                fieldDefinitions:
                  type: object
                  required:
                    - sections
                  properties:
                    sections:
                      type: array
                      items:
                        type: object
                        required:
                          - key
                          - label
                          - fields
                        properties:
                          key:
                            type: string
                          label:
                            type: string
                          fields:
                            type: array
                            items:
                              type: object
                              required:
                                - key
                                - label
                                - type
                                - requiredAt
                              properties:
                                key:
                                  type: string
                                label:
                                  type: string
                                type:
                                  type: string
                                requiredAt:
                                  type: string
                                  format: date-time
                reason:
                  type: string
              example:
                fieldDefinitions:
                  sections:
                    - key: service_details
                      label: Service details
                      fields:
                        - key: requested_effective_date
                          label: Requested effective date
                          type: DATE
                          requiredAt: OPTIONAL
                reason: Add the requested effective date to support work.
            example:
              fieldDefinitions:
                sections:
                  - key: service_details
                    label: Service details
                    fields:
                      - key: requested_effective_date
                        label: Requested effective date
                        type: DATE
                        requiredAt: OPTIONAL
              reason: Add the requested effective date to support work.
  /v1/servicing/admin/task-types/{taskTypeCode}/completion-field-definitions:
    get:
      tags:
        - Servicing administration
      operationId: getTaskCompletionFieldDefinitions
      summary: Retrieve task completion fields
      description: Returns the current completion-field schema owned by an existing task type.
      x-permission: ADMIN_SERVICING_CONFIG
      x-idempotent: false
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: taskTypeCode
          in: path
          required: true
          description: Stable opaque taskTypeCode identifier.
          schema:
            type: string
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - taskTypeCode
                  - completionFieldDefinitions
                properties:
                  taskTypeCode:
                    type: string
                  completionFieldDefinitions:
                    type: object
                    required:
                      - sections
                    properties:
                      sections:
                        type: array
                        items:
                          type: object
              example:
                taskTypeCode: COLLECTIONS_OUTREACH
                completionFieldDefinitions:
                  sections: []
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
    put:
      tags:
        - Servicing administration
      operationId: replaceTaskCompletionFieldDefinitions
      summary: Replace task completion fields
      description: Replaces the closed completion-field configuration for an existing task type without creating a secondary
        form lifecycle.
      x-permission: ADMIN_SERVICING_CONFIG
      x-idempotent: true
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: taskTypeCode
          in: path
          required: true
          description: Stable opaque taskTypeCode identifier.
          schema:
            type: string
        - name: Idempotency-Key
          in: header
          required: false
          description: Optional replay key for this logical mutation. Omission creates a fresh server-owned key for this attempt;
            blank, repeated, or longer-than-50-character values are rejected.
          schema:
            type: string
            minLength: 1
            maxLength: 50
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - resourceId
                  - taskTypeCode
                  - changes
                properties:
                  resourceId:
                    type: integer
                  taskTypeCode:
                    type: string
                  changes:
                    type: object
                    required:
                      - fieldKeys
                    properties:
                      fieldKeys:
                        type: array
                        items:
                          type: object
              example:
                resourceId: 21
                taskTypeCode: COLLECTIONS_OUTREACH
                changes:
                  fieldKeys: []
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
        "409":
          $ref: "#/components/responses/Servicing409Error"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - completionFieldDefinitions
                - reason
              properties:
                completionFieldDefinitions:
                  type: object
                  required:
                    - sections
                  properties:
                    sections:
                      type: array
                      items:
                        type: object
                reason:
                  type: string
              example:
                completionFieldDefinitions:
                  sections: []
                reason: Align completion evidence with the current workflow.
            example:
              completionFieldDefinitions:
                sections: []
              reason: Align completion evidence with the current workflow.
  /v1/servicing/verification/sessions:
    post:
      tags:
        - Verification
      operationId: startServicingVerificationSession
      summary: Start a verification session
      description: Starts a purpose-bound session and returns policy-selected prompts without exposing expected answers.
      x-permission: CREATE_SERVICING_VERIFICATION
      x-idempotent: true
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: Idempotency-Key
          in: header
          required: false
          description: Optional replay key for this logical mutation. Omission creates a fresh server-owned key for this attempt;
            blank, repeated, or longer-than-50-character values are rejected.
          schema:
            type: string
            minLength: 1
            maxLength: 50
      responses:
        "201":
          description: Created.
          content:
            application/json:
              schema:
                type: object
                required:
                  - sessionId
                  - status
                  - attemptLimit
                  - prompts
                  - resourceId
                properties:
                  sessionId:
                    type: integer
                  status:
                    type: string
                    description: Current normalized lifecycle state.
                  attemptLimit:
                    type: integer
                  prompts:
                    type: array
                    items:
                      type: object
                      required:
                        - questionCode
                        - prompt
                      properties:
                        questionCode:
                          type: string
                        prompt:
                          type: string
                  resourceId:
                    type: integer
              example:
                sessionId: 7401
                status: PENDING
                attemptLimit: 3
                prompts:
                  - questionCode: RECENT_PAYMENT_AMOUNT
                    prompt: What was the amount of your most recent payment?
                resourceId: 7401
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
        "409":
          $ref: "#/components/responses/Servicing409Error"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - customerRef
                - interactionId
                - purpose
              properties:
                customerRef:
                  type: string
                interactionId:
                  type: integer
                caseId:
                  type: integer
                  description: Stable opaque servicing case identifier.
                purpose:
                  type: string
              example:
                customerRef: "123"
                interactionId: 3001
                caseId: 1001
                purpose: ACCOUNT_DISCLOSURE
            example:
              customerRef: "123"
              interactionId: 3001
              caseId: 1001
              purpose: ACCOUNT_DISCLOSURE
  /v1/servicing/verification/sessions/{sessionId}/answers:
    post:
      tags:
        - Verification
      operationId: submitServicingVerificationAnswers
      summary: Submit verification answers
      description: Evaluates one complete attempt, updates the linked interaction assurance state, and never echoes or logs
        raw answers.
      x-permission: COMPLETE_SERVICING_VERIFICATION
      x-idempotent: true
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: sessionId
          in: path
          required: true
          description: Positive numeric session identifier.
          schema:
            type: integer
            format: int64
            minimum: 1
        - name: Idempotency-Key
          in: header
          required: false
          description: Optional replay key for this logical mutation. Omission creates a fresh server-owned key for this attempt;
            blank, repeated, or longer-than-50-character values are rejected.
          schema:
            type: string
            minLength: 1
            maxLength: 50
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - sessionId
                  - status
                  - attemptsRemaining
                  - resourceId
                properties:
                  sessionId:
                    type: integer
                  status:
                    type: string
                    description: Current normalized lifecycle state.
                  attemptsRemaining:
                    type: integer
                  resourceId:
                    type: integer
              example:
                sessionId: 7401
                status: VERIFIED
                attemptsRemaining: 2
                resourceId: 7401
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
        "409":
          $ref: "#/components/responses/Servicing409Error"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - answers
              properties:
                answers:
                  type: array
                  items:
                    type: object
                    required:
                      - questionCode
                      - answer
                    properties:
                      questionCode:
                        type: string
                      answer:
                        type: string
              example:
                answers:
                  - questionCode: RECENT_PAYMENT_AMOUNT
                    answer: "517.14"
            example:
              answers:
                - questionCode: RECENT_PAYMENT_AMOUNT
                  answer: "517.14"
  /v1/servicing/privacy-requests:
    post:
      tags:
        - Privacy requests
      operationId: createPrivacyRequest
      summary: Create a privacy-rights request
      description: Records the request, computes its deadline, and creates sourced compliance-review work.
      x-permission: CREATE_SERVICING_PRIVACY_REQUEST
      x-idempotent: true
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: Idempotency-Key
          in: header
          required: false
          description: Optional replay key for this logical mutation. Omission creates a fresh server-owned key for this attempt;
            blank, repeated, or longer-than-50-character values are rejected.
          schema:
            type: string
            minLength: 1
            maxLength: 50
      responses:
        "201":
          description: Created.
          content:
            application/json:
              schema:
                type: object
                required:
                  - requestId
                  - status
                  - statutoryDueAt
                  - reviewTaskId
                  - resourceId
                properties:
                  requestId:
                    type: integer
                  status:
                    type: string
                    description: Current normalized lifecycle state.
                  statutoryDueAt:
                    type: string
                    format: date-time
                  reviewTaskId:
                    type: integer
                  resourceId:
                    type: integer
              example:
                requestId: 7501
                status: RECEIVED
                statutoryDueAt: 2026-09-08T23:59:59-07:00
                reviewTaskId: 3302
                resourceId: 7501
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
        "409":
          $ref: "#/components/responses/Servicing409Error"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - customerRef
                - requestType
                - regime
                - summary
              properties:
                customerRef:
                  type: string
                requestType:
                  type: string
                regime:
                  type: string
                summary:
                  type: string
                caseId:
                  type: integer
                  description: Stable opaque servicing case identifier.
                sourceInteractionId:
                  type: integer
              example:
                customerRef: "123"
                requestType: DELETION
                regime: CCPA_CPRA
                summary: Customer requests deletion of personal information.
                caseId: 1001
                sourceInteractionId: 3001
            example:
              customerRef: "123"
              requestType: DELETION
              regime: CCPA_CPRA
              summary: Customer requests deletion of personal information.
              caseId: 1001
              sourceInteractionId: 3001
    get:
      tags:
        - Privacy requests
      operationId: listPrivacyRequests
      summary: List privacy-rights requests
      description: Lists tracked privacy-rights requests with their statutory deadlines, review-task state, and allowed
        transitions. dueFrom and dueTo bound the statutory deadline and must be supplied together; sort accepts
        statutoryDueAt, receivedAt, status, or requestType.
      x-permission: READ_SERVICING_PRIVACY_REQUEST
      x-idempotent: false
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: status
          in: query
          required: false
          description: Repeat to include multiple states.
          schema:
            type: string
            enum:
              - INTAKE
              - IN_FULFILLMENT
              - FULFILLED
              - REJECTED
              - REFERRED
        - name: requestType
          in: query
          required: false
          description: Repeat to include multiple request types.
          schema:
            type: string
            enum:
              - ACCESS
              - DELETION
              - CORRECTION
              - OPT_OUT
              - OTHER
        - name: regime
          in: query
          required: false
          description: Repeat to include multiple privacy regimes.
          schema:
            type: string
            enum:
              - CCPA_CPRA
              - OTHER_STATE
              - FEDERAL
        - name: customerRef
          in: query
          required: false
          description: Exact customer reference.
          schema:
            type: string
        - name: caseId
          in: query
          required: false
          description: Case the request is linked to.
          schema:
            type: integer
        - name: dueFrom
          in: query
          required: false
          description: Inclusive timestamp lower bound.
          schema:
            type: string
            format: date-time
        - name: dueTo
          in: query
          required: false
          description: Exclusive timestamp upper bound.
          schema:
            type: string
            format: date-time
        - name: limit
          in: query
          required: false
          description: Maximum rows to return; defaults to 50.
          schema:
            type: integer
            minimum: 1
            maximum: 200
            default: 50
        - name: offset
          in: query
          required: false
          description: Zero-based row offset; defaults to 0.
          schema:
            type: integer
            minimum: 0
            default: 0
        - name: sort
          in: query
          required: false
          description: Allowlisted sort field for this collection.
          schema:
            type: string
        - name: order
          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:
                  - items
                  - limit
                  - offset
                  - hasMore
                properties:
                  items:
                    type: array
                    items:
                      type: object
                      required:
                        - privacyRequestId
                        - externalRequestRef
                        - customerRef
                        - requestType
                        - regime
                        - summary
                        - status
                        - caseId
                        - externalCaseRef
                        - sourceInteractionId
                        - reviewTaskId
                        - reviewTaskAssignedWorkerId
                        - reviewTaskStatus
                        - receivedAt
                        - statutoryDueAt
                        - allowedTransitions
                      properties:
                        privacyRequestId:
                          type: integer
                        externalRequestRef:
                          type: string
                        customerRef:
                          type: string
                        requestType:
                          type: string
                        regime:
                          type: string
                        summary:
                          type: string
                        status:
                          type: string
                          description: Current normalized lifecycle state.
                        caseId:
                          type: integer
                          description: Stable opaque servicing case identifier.
                        externalCaseRef:
                          type: string
                        sourceInteractionId:
                          type: integer
                        reviewTaskId:
                          type: integer
                        reviewTaskAssignedWorkerId:
                          type: integer
                        reviewTaskStatus:
                          type: string
                        receivedAt:
                          type: string
                          format: date-time
                        statutoryDueAt:
                          type: string
                          format: date-time
                        allowedTransitions:
                          type: array
                          items:
                            type: string
                  limit:
                    type: integer
                  offset:
                    type: integer
                  hasMore:
                    type: boolean
              example:
                items:
                  - privacyRequestId: 7501
                    externalRequestRef: LE-PRIV-7501
                    customerRef: "123"
                    requestType: DELETION
                    regime: CCPA_CPRA
                    summary: Customer requests deletion of personal information.
                    status: INTAKE
                    caseId: 1001
                    externalCaseRef: LE-CASE-1001
                    sourceInteractionId: 3001
                    reviewTaskId: 3302
                    reviewTaskAssignedWorkerId: 4101
                    reviewTaskStatus: ACCEPTED
                    receivedAt: 2026-07-25T18:30:00Z
                    statutoryDueAt: 2026-09-08T18:30:00Z
                    allowedTransitions:
                      - IN_FULFILLMENT
                      - FULFILLED
                      - REJECTED
                      - REFERRED
                limit: 50
                offset: 0
                hasMore: false
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
  /v1/servicing/privacy-requests/{requestId}/fulfill:
    post:
      tags:
        - Privacy requests
      operationId: fulfillPrivacyRequest
      summary: Fulfill a privacy-rights request
      description: Records a terminal fulfillment, rejection, or referral while preserving legal holds and evidence.
      x-permission: FULFILL_SERVICING_PRIVACY_REQUEST
      x-idempotent: true
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: requestId
          in: path
          required: true
          description: Positive numeric request identifier.
          schema:
            type: integer
            format: int64
            minimum: 1
        - name: Idempotency-Key
          in: header
          required: false
          description: Optional replay key for this logical mutation. Omission creates a fresh server-owned key for this attempt;
            blank, repeated, or longer-than-50-character values are rejected.
          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:
                      - status
                    properties:
                      status:
                        type: string
                        description: Current normalized lifecycle state.
              example:
                resourceId: 7501
                changes:
                  status: FULFILLED
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
        "409":
          $ref: "#/components/responses/Servicing409Error"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - outcome
                - outcomeReason
              properties:
                outcome:
                  type: string
                outcomeReason:
                  type: string
                evidenceIds:
                  type: array
                  description: Evidence records supporting the request.
                  items:
                    type: integer
              example:
                outcome: FULFILLED
                outcomeReason: Verified export delivered through the approved channel.
                evidenceIds:
                  - 8801
            example:
              outcome: FULFILLED
              outcomeReason: Verified export delivered through the approved channel.
              evidenceIds:
                - 8801
  /v1/servicing/cases/{caseId}/promises/{promiseId}/revise:
    post:
      tags:
        - Promises
      operationId: reviseCasePromise
      summary: Revise or cancel a promise
      description: Cancels or supersedes a promise under current guardrails while preserving the original commitment history.
      x-permission: UPDATE_SERVICING_PROMISE
      x-idempotent: true
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: caseId
          in: path
          required: true
          description: Positive numeric case identifier.
          schema:
            type: integer
            format: int64
            minimum: 1
        - name: promiseId
          in: path
          required: true
          description: Positive numeric promise identifier.
          schema:
            type: integer
            format: int64
            minimum: 1
        - name: Idempotency-Key
          in: header
          required: false
          description: Optional replay key for this logical mutation. Omission creates a fresh server-owned key for this attempt;
            blank, repeated, or longer-than-50-character values are rejected.
          schema:
            type: string
            minLength: 1
            maxLength: 50
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - outcome
                  - promiseId
                  - supersedesPromiseId
                  - resourceId
                properties:
                  outcome:
                    type: string
                  promiseId:
                    type: integer
                  supersedesPromiseId:
                    type: integer
                  resourceId:
                    type: integer
              example:
                outcome: COMPLETED
                promiseId: 6102
                supersedesPromiseId: 6101
                resourceId: 6102
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
        "409":
          $ref: "#/components/responses/Servicing409Error"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - operation
                - reason
              properties:
                operation:
                  type: string
                planType:
                  type: string
                promiseDate:
                  type: string
                  format: date
                promiseAmount:
                  type: object
                  required:
                    - amount
                    - currency
                  properties:
                    amount:
                      type: integer
                      description: Decimal monetary value using the representation declared by this operation.
                    currency:
                      type: string
                      pattern: ^[A-Z]{3}$
                      description: ISO 4217 currency code.
                reason:
                  type: string
              example:
                operation: REPLACE
                planType: SINGLE
                promiseDate: 2026-08-08
                promiseAmount:
                  amount: 250
                  currency: USD
                reason: Customer requested a one-week extension.
            example:
              operation: REPLACE
              planType: SINGLE
              promiseDate: 2026-08-08
              promiseAmount:
                amount: 250
                currency: USD
              reason: Customer requested a one-week extension.
  /v1/servicing/cases/{caseId}/payment-requests:
    post:
      tags:
        - Governed operations
      operationId: prepareServicingPayment
      summary: Prepare a customer-authorized payment
      description: Executes a grounded authorized payment immediately when allowed or creates the exact approval/manual
        request required by policy.
      x-permission: CREATE_SERVICING_PAYMENT_REQUEST
      x-idempotent: true
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: caseId
          in: path
          required: true
          description: Positive numeric case identifier.
          schema:
            type: integer
            format: int64
            minimum: 1
        - name: Idempotency-Key
          in: header
          required: false
          description: Optional replay key for this logical mutation. Omission creates a fresh server-owned key for this attempt;
            blank, repeated, or longer-than-50-character values are rejected.
          schema:
            type: string
            minLength: 1
            maxLength: 50
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - outcome
                  - paymentRef
                  - resourceId
                properties:
                  outcome:
                    type: string
                  paymentRef:
                    type: string
                  resourceId:
                    type: integer
              example:
                outcome: COMPLETED
                paymentRef: payment-9001
                resourceId: 9001
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
        "409":
          $ref: "#/components/responses/Servicing409Error"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - loanRef
                - instrumentId
                - amount
                - valueDate
                - authorizationRef
                - reason
              properties:
                loanRef:
                  type: string
                instrumentId:
                  type: integer
                amount:
                  type: object
                  description: Decimal monetary value using the representation declared by this operation.
                  required:
                    - amount
                    - currency
                  properties:
                    amount:
                      type: number
                      description: Decimal monetary value using the representation declared by this operation.
                    currency:
                      type: string
                      pattern: ^[A-Z]{3}$
                      description: ISO 4217 currency code.
                valueDate:
                  type: string
                  format: date
                authorizationRef:
                  type: string
                reason:
                  type: string
              example:
                loanRef: "456"
                instrumentId: 7001
                amount:
                  amount: 202.36
                  currency: USD
                valueDate: 2026-08-01
                authorizationRef: auth-9f2
                reason: Customer authorized the cure payment.
            example:
              loanRef: "456"
              instrumentId: 7001
              amount:
                amount: 202.36
                currency: USD
              valueDate: 2026-08-01
              authorizationRef: auth-9f2
              reason: Customer authorized the cure payment.
  /v1/servicing/cases/{caseId}/external-payments:
    post:
      tags:
        - Governed operations
      operationId: recordServicingExternalPayment
      summary: Record an external payment
      description: Records a payment from an outside system and either posts it through the typed LMS boundary or creates
        reconciliation work.
      x-permission: RECORD_SERVICING_EXTERNAL_PAYMENT
      x-idempotent: true
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: caseId
          in: path
          required: true
          description: Positive numeric case identifier.
          schema:
            type: integer
            format: int64
            minimum: 1
        - name: Idempotency-Key
          in: header
          required: false
          description: Optional replay key for this logical mutation. Omission creates a fresh server-owned key for this attempt;
            blank, repeated, or longer-than-50-character values are rejected.
          schema:
            type: string
            minLength: 1
            maxLength: 50
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - outcome
                  - paymentRef
                  - resourceId
                properties:
                  outcome:
                    type: string
                  paymentRef:
                    type: string
                  resourceId:
                    type: integer
              example:
                outcome: COMPLETED
                paymentRef: payment-9002
                resourceId: 9002
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
        "409":
          $ref: "#/components/responses/Servicing409Error"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - loanRef
                - amount
                - effectiveDate
                - externalRecordRef
                - source
                - reason
                - evidenceIds
              properties:
                loanRef:
                  type: string
                amount:
                  type: object
                  description: Decimal monetary value using the representation declared by this operation.
                  required:
                    - amount
                    - currency
                  properties:
                    amount:
                      type: integer
                      description: Decimal monetary value using the representation declared by this operation.
                    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.
                postToLedger:
                  type: boolean
                reason:
                  type: string
                evidenceIds:
                  type: array
                  description: Evidence records supporting the request.
                  items:
                    type: integer
              example:
                loanRef: "456"
                amount:
                  amount: 125
                  currency: USD
                effectiveDate: 2026-07-25
                externalRecordRef: lockbox-2026-1001
                source: EXTERNAL
                postToLedger: true
                reason: Verified lockbox receipt.
                evidenceIds:
                  - 8801
            example:
              loanRef: "456"
              amount:
                amount: 125
                currency: USD
              effectiveDate: 2026-07-25
              externalRecordRef: lockbox-2026-1001
              source: EXTERNAL
              postToLedger: true
              reason: Verified lockbox receipt.
              evidenceIds:
                - 8801
  /v1/servicing/cases/{caseId}/contact-consent-updates:
    post:
      tags:
        - Governed operations
      operationId: updateServicingContactConsent
      summary: Update contact or consent
      description: Applies a typed contact-point or consent change through the authoritative LMS boundary under current policy.
      x-permission: UPDATE_SERVICING_CONTACT_CONSENT
      x-idempotent: true
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: caseId
          in: path
          required: true
          description: Positive numeric case identifier.
          schema:
            type: integer
            format: int64
            minimum: 1
        - name: Idempotency-Key
          in: header
          required: false
          description: Optional replay key for this logical mutation. Omission creates a fresh server-owned key for this attempt;
            blank, repeated, or longer-than-50-character values are rejected.
          schema:
            type: string
            minLength: 1
            maxLength: 50
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - outcome
                  - customerRef
                  - resourceId
                properties:
                  outcome:
                    type: string
                  customerRef:
                    type: string
                  resourceId:
                    type: integer
              example:
                outcome: COMPLETED
                customerRef: "123"
                resourceId: 123
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
        "409":
          $ref: "#/components/responses/Servicing409Error"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - customerRef
                - operation
                - reason
              properties:
                customerRef:
                  type: string
                operation:
                  type: string
                contactPointRef:
                  type: string
                canReceiveSms:
                  type: boolean
                effectiveAt:
                  type: string
                  format: date-time
                reason:
                  type: string
              example:
                customerRef: "123"
                operation: UPDATE_SMS_PERMISSION
                contactPointRef: phone-1
                canReceiveSms: false
                effectiveAt: 2026-07-25T18:30:00Z
                reason: Customer opted out by SMS.
            example:
              customerRef: "123"
              operation: UPDATE_SMS_PERMISSION
              contactPointRef: phone-1
              canReceiveSms: false
              effectiveAt: 2026-07-25T18:30:00Z
              reason: Customer opted out by SMS.
  /v1/servicing/cases/{caseId}/restriction-changes:
    post:
      tags:
        - Governed operations
      operationId: changeServicingRestriction
      summary: Apply or clear an account restriction
      description: Applies or clears one typed authoritative restriction; protective applications and relaxations follow
        separate action-specific policy.
      x-permission: CHANGE_SERVICING_RESTRICTION
      x-idempotent: true
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: caseId
          in: path
          required: true
          description: Positive numeric case identifier.
          schema:
            type: integer
            format: int64
            minimum: 1
        - name: Idempotency-Key
          in: header
          required: false
          description: Optional replay key for this logical mutation. Omission creates a fresh server-owned key for this attempt;
            blank, repeated, or longer-than-50-character values are rejected.
          schema:
            type: string
            minLength: 1
            maxLength: 50
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - outcome
                  - restrictionRef
                  - resourceId
                properties:
                  outcome:
                    type: string
                  restrictionRef:
                    type: string
                  resourceId:
                    type: integer
              example:
                outcome: COMPLETED
                restrictionRef: restriction-41
                resourceId: 41
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
        "409":
          $ref: "#/components/responses/Servicing409Error"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - customerRef
                - operation
                - restrictionType
                - effectiveAt
                - reason
                - evidenceIds
              properties:
                customerRef:
                  type: string
                loanRef:
                  type: string
                operation:
                  type: string
                restrictionType:
                  type: string
                effectiveAt:
                  type: string
                  format: date-time
                reason:
                  type: string
                evidenceIds:
                  type: array
                  description: Evidence records supporting the request.
                  items:
                    type: integer
              example:
                customerRef: "123"
                loanRef: "456"
                operation: APPLY
                restrictionType: CEASE_COMMUNICATIONS
                effectiveAt: 2026-07-25T18:30:00Z
                reason: Verified written cease request.
                evidenceIds:
                  - 8801
            example:
              customerRef: "123"
              loanRef: "456"
              operation: APPLY
              restrictionType: CEASE_COMMUNICATIONS
              effectiveAt: 2026-07-25T18:30:00Z
              reason: Verified written cease request.
              evidenceIds:
                - 8801
  /v1/servicing/cases/{caseId}/bankruptcy-updates:
    post:
      tags:
        - Governed operations
      operationId: updateServicingBankruptcy
      summary: Update a bankruptcy record
      description: Records a verified bankruptcy change and invokes only the typed authoritative restrictions required by
        current policy.
      x-permission: UPDATE_SERVICING_BANKRUPTCY
      x-idempotent: true
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: caseId
          in: path
          required: true
          description: Positive numeric case identifier.
          schema:
            type: integer
            format: int64
            minimum: 1
        - name: Idempotency-Key
          in: header
          required: false
          description: Optional replay key for this logical mutation. Omission creates a fresh server-owned key for this attempt;
            blank, repeated, or longer-than-50-character values are rejected.
          schema:
            type: string
            minLength: 1
            maxLength: 50
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - outcome
                  - bankruptcyRef
                  - resourceId
                properties:
                  outcome:
                    type: string
                  bankruptcyRef:
                    type: string
                  resourceId:
                    type: integer
              example:
                outcome: COMPLETED
                bankruptcyRef: bankruptcy-81
                resourceId: 81
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
        "409":
          $ref: "#/components/responses/Servicing409Error"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - customerRef
                - operation
                - reason
                - evidenceIds
              properties:
                customerRef:
                  type: string
                loanRefs:
                  type: array
                  items:
                    type: string
                operation:
                  type: string
                chapter:
                  type: string
                filedOn:
                  type: string
                courtReference:
                  type: string
                reason:
                  type: string
                evidenceIds:
                  type: array
                  description: Evidence records supporting the request.
                  items:
                    type: integer
              example:
                customerRef: "123"
                loanRefs:
                  - "456"
                operation: FILED
                chapter: CHAPTER_7
                filedOn: 2026-07-24
                courtReference: court-ref-7781
                reason: Verified court notice received.
                evidenceIds:
                  - 8801
            example:
              customerRef: "123"
              loanRefs:
                - "456"
              operation: FILED
              chapter: CHAPTER_7
              filedOn: 2026-07-24
              courtReference: court-ref-7781
              reason: Verified court notice received.
              evidenceIds:
                - 8801
  /v1/servicing/cases/{caseId}/responses:
    post:
      tags:
        - Governed operations
      operationId: sendCaseResponse
      summary: Send or log a case response
      description: Creates the owning interaction response directly after current-fact checks; it does not create an action request.
      x-permission: SEND_SERVICING_RESPONSE
      x-idempotent: true
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: caseId
          in: path
          required: true
          description: Positive numeric case identifier.
          schema:
            type: integer
            format: int64
            minimum: 1
        - name: Idempotency-Key
          in: header
          required: false
          description: Optional replay key for this logical mutation. Omission creates a fresh server-owned key for this attempt;
            blank, repeated, or longer-than-50-character values are rejected.
          schema:
            type: string
            minLength: 1
            maxLength: 50
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - outcome
                  - interactionId
                  - resourceId
                properties:
                  outcome:
                    type: string
                  interactionId:
                    type: integer
                  resourceId:
                    type: integer
              example:
                outcome: COMPLETED
                interactionId: 3003
                resourceId: 3003
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
        "409":
          $ref: "#/components/responses/Servicing409Error"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - channel
                - contactPointRef
                - reasonCode
                - body
                - reason
              properties:
                channel:
                  type: string
                contactPointRef:
                  type: string
                reasonCode:
                  type: string
                  description: Configured structured reason code.
                subject:
                  type: string
                body:
                  type: string
                reason:
                  type: string
              example:
                channel: EMAIL
                contactPointRef: email-1
                reasonCode: CASE_RESPONSE
                subject: Your servicing request
                body: We completed our review.
                reason: Respond to the customer with the verified outcome.
            example:
              channel: EMAIL
              contactPointRef: email-1
              reasonCode: CASE_RESPONSE
              subject: Your servicing request
              body: We completed our review.
              reason: Respond to the customer with the verified outcome.
  /v1/servicing/cases/{caseId}/follow-up-tasks:
    post:
      tags:
        - Governed operations
      operationId: createCaseFollowUpTask
      summary: Create internal follow-up work
      description: Creates typed internal case work directly. Customer contact is scheduled through the interaction endpoint.
      x-permission: CREATE_SERVICING_FOLLOW_UP_TASK
      x-idempotent: true
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: caseId
          in: path
          required: true
          description: Positive numeric case identifier.
          schema:
            type: integer
            format: int64
            minimum: 1
        - name: Idempotency-Key
          in: header
          required: false
          description: Optional replay key for this logical mutation. Omission creates a fresh server-owned key for this attempt;
            blank, repeated, or longer-than-50-character values are rejected.
          schema:
            type: string
            minLength: 1
            maxLength: 50
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - outcome
                  - taskId
                  - resourceId
                properties:
                  outcome:
                    type: string
                  taskId:
                    type: integer
                  resourceId:
                    type: integer
              example:
                outcome: COMPLETED
                taskId: 2002
                resourceId: 2002
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
        "409":
          $ref: "#/components/responses/Servicing409Error"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - taskTypeCode
                - dueDate
                - reason
              properties:
                taskTypeCode:
                  type: string
                dueDate:
                  type: string
                  format: date
                queueCode:
                  type: string
                priority:
                  type: string
                summary:
                  type: string
                reason:
                  type: string
              example:
                taskTypeCode: REVIEW_PROMISE_OUTCOME
                dueDate: 2026-08-02
                queueCode: COLLECTIONS
                priority: NORMAL
                summary: Review the promise after the grace window.
                reason: Promise outcome requires follow-up.
            example:
              taskTypeCode: REVIEW_PROMISE_OUTCOME
              dueDate: 2026-08-02
              queueCode: COLLECTIONS
              priority: NORMAL
              summary: Review the promise after the grace window.
              reason: Promise outcome requires follow-up.
  /v1/servicing/cases/{caseId}/payment-support-reviews:
    post:
      tags:
        - Governed operations
      operationId: requestPaymentSupportReview
      summary: Create payment-support review work
      description: Creates specialist work directly when payment support needs human investigation; it does not manufacture an
        approval request.
      x-permission: REQUEST_SERVICING_PAYMENT_SUPPORT_REVIEW
      x-idempotent: true
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: caseId
          in: path
          required: true
          description: Positive numeric case identifier.
          schema:
            type: integer
            format: int64
            minimum: 1
        - name: Idempotency-Key
          in: header
          required: false
          description: Optional replay key for this logical mutation. Omission creates a fresh server-owned key for this attempt;
            blank, repeated, or longer-than-50-character values are rejected.
          schema:
            type: string
            minLength: 1
            maxLength: 50
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - outcome
                  - taskId
                  - resourceId
                properties:
                  outcome:
                    type: string
                  taskId:
                    type: integer
                  resourceId:
                    type: integer
              example:
                outcome: COMPLETED
                taskId: 2003
                resourceId: 2003
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
        "409":
          $ref: "#/components/responses/Servicing409Error"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - loanRef
                - issueCode
                - summary
                - reason
              properties:
                loanRef:
                  type: string
                issueCode:
                  type: string
                summary:
                  type: string
                reason:
                  type: string
                evidenceIds:
                  type: array
                  description: Evidence records supporting the request.
                  items:
                    type: integer
              example:
                loanRef: "456"
                issueCode: PAYMENT_NOT_POSTED
                summary: Customer supplied a confirmation but the LMS has no posted payment.
                reason: Investigate the authoritative payment state.
                evidenceIds:
                  - 8801
            example:
              loanRef: "456"
              issueCode: PAYMENT_NOT_POSTED
              summary: Customer supplied a confirmation but the LMS has no posted payment.
              reason: Investigate the authoritative payment state.
              evidenceIds:
                - 8801
  /v1/servicing/cases/{caseId}/action-requests:
    get:
      tags:
        - Action requests
      operationId: listCaseActionRequests
      summary: List case action requests
      description: Lists only requests actually materialized by approval, deferred, unavailable, or manual operation outcomes,
        with the caller-specific allowed actions on each item.
      x-permission: READ_SERVICING_CASE
      x-idempotent: false
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: caseId
          in: path
          required: true
          description: Positive numeric case identifier.
          schema:
            type: integer
            format: int64
            minimum: 1
        - name: limit
          in: query
          required: false
          description: Maximum rows to return; defaults to 50.
          schema:
            type: integer
            minimum: 1
            maximum: 200
            default: 50
        - name: offset
          in: query
          required: false
          description: Zero-based row offset; defaults to 0.
          schema:
            type: integer
            minimum: 0
            default: 0
        - name: status
          in: query
          required: false
          description: Repeat to include multiple action-request states.
          schema:
            type: string
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - items
                  - limit
                  - offset
                  - hasMore
                  - total
                properties:
                  items:
                    type: array
                    items:
                      type: object
                      required:
                        - actionRequestId
                        - externalActionRef
                        - caseId
                        - externalCaseRef
                        - customerRef
                        - actionType
                        - riskClass
                        - status
                        - preparedByActorType
                        - preparedByWorkerId
                        - approvalRequired
                        - approvalPermissionCode
                        - allowedActions
                        - requestPayload
                        - createdAt
                        - lastUpdatedAt
                      properties:
                        actionRequestId:
                          type: integer
                          description: Stable opaque action-request identifier.
                        externalActionRef:
                          type: string
                        caseId:
                          type: integer
                          description: Stable opaque servicing case identifier.
                        externalCaseRef:
                          type: string
                        customerRef:
                          type: string
                        actionType:
                          type: string
                        riskClass:
                          type: string
                        status:
                          type: string
                          description: Current normalized lifecycle state.
                        preparedByActorType:
                          type: string
                        preparedByWorkerId:
                          type: integer
                        approvalRequired:
                          type: boolean
                        approvalPermissionCode:
                          type: string
                        allowedActions:
                          type: array
                          items:
                            type: string
                        requestPayload:
                          type: object
                          required:
                            - loanRef
                            - planType
                            - promiseDate
                          properties:
                            loanRef:
                              type: string
                            planType:
                              type: string
                            promiseDate:
                              type: string
                              format: date
                        createdAt:
                          type: string
                          format: date-time
                        lastUpdatedAt:
                          type: string
                          format: date-time
                  limit:
                    type: integer
                  offset:
                    type: integer
                  hasMore:
                    type: boolean
                  total:
                    type: integer
              example:
                items:
                  - actionRequestId: 6001
                    externalActionRef: LE-ACTION-6001
                    caseId: 1001
                    externalCaseRef: LE-CASE-1001
                    customerRef: "123"
                    actionType: AR_002
                    riskClass: R2
                    status: APPROVAL_REQUIRED
                    preparedByActorType: HUMAN
                    preparedByWorkerId: 4101
                    approvalRequired: true
                    approvalPermissionCode: APPROVE_SERVICING_PROMISE
                    allowedActions:
                      - APPROVE
                      - REJECT
                    requestPayload:
                      loanRef: "456"
                      planType: SINGLE
                      promiseDate: 2026-08-01
                    createdAt: 2026-07-25T18:30:00Z
                    lastUpdatedAt: 2026-07-25T18:30:00Z
                limit: 50
                offset: 0
                hasMore: false
                total: 1
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
  /v1/servicing/action-requests/{actionRequestId}/manual-complete:
    post:
      tags:
        - Action requests
      operationId: manuallyCompleteActionRequest
      summary: Complete a manual action request
      description: Records evidence-backed completion only for a request in MANUAL_EXECUTION_REQUIRED.
      x-permission: MANUAL_COMPLETE_SERVICING_ACTION_REQUEST
      x-idempotent: true
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: actionRequestId
          in: path
          required: true
          description: Positive numeric actionRequest identifier.
          schema:
            type: integer
            format: int64
            minimum: 1
        - name: Idempotency-Key
          in: header
          required: false
          description: Optional replay key for this logical mutation. Omission creates a fresh server-owned key for this attempt;
            blank, repeated, or longer-than-50-character values are rejected.
          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:
                      - status
                      - resultCode
                    properties:
                      status:
                        type: string
                        description: Current normalized lifecycle state.
                      resultCode:
                        type: string
              example:
                resourceId: 6001
                changes:
                  status: COMPLETED
                  resultCode: COMPLETED_EXTERNALLY
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
        "409":
          $ref: "#/components/responses/Servicing409Error"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - outcomeCode
                - reason
                - evidenceIds
              properties:
                outcomeCode:
                  type: string
                reason:
                  type: string
                evidenceIds:
                  type: array
                  description: Evidence records supporting the request.
                  items:
                    type: integer
                externalResultRef:
                  type: string
              example:
                outcomeCode: COMPLETED_EXTERNALLY
                reason: The external system completed the change.
                evidenceIds:
                  - 8801
                externalResultRef: external-result-71
            example:
              outcomeCode: COMPLETED_EXTERNALLY
              reason: The external system completed the change.
              evidenceIds:
                - 8801
              externalResultRef: external-result-71
  /v1/servicing/workers/me/presence:
    post:
      tags:
        - Workforce
      operationId: updateWorkerPresence
      summary: Update my worker presence
      description: Sets the authenticated HUMAN worker’s availability and channel set.
      x-permission: UPDATE_SERVICING_WORKER_PRESENCE
      x-idempotent: true
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: Idempotency-Key
          in: header
          required: false
          description: Optional replay key for this logical mutation. Omission creates a fresh server-owned key for this attempt;
            blank, repeated, or longer-than-50-character values are rejected.
          schema:
            type: string
            minLength: 1
            maxLength: 50
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - workerId
                  - state
                  - channels
                  - resourceId
                properties:
                  workerId:
                    type: integer
                  state:
                    type: string
                  channels:
                    type: array
                    items:
                      type: string
                  resourceId:
                    type: integer
              example:
                workerId: 4101
                state: AVAILABLE
                channels:
                  - PHONE
                  - EMAIL
                resourceId: 4101
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
        "409":
          $ref: "#/components/responses/Servicing409Error"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - state
                - channels
              properties:
                state:
                  type: string
                channels:
                  type: array
                  items:
                    type: string
              example:
                state: AVAILABLE
                channels:
                  - PHONE
                  - EMAIL
            example:
              state: AVAILABLE
              channels:
                - PHONE
                - EMAIL
  /v1/servicing/cases/{caseId}/effects:
    get:
      tags:
        - Case effects
      operationId: listCaseEffects
      summary: List case effects
      description: Lists workflow-created typed effects and redacted execution state; callers cannot create effects directly.
      x-permission: READ_SERVICING_CASE
      x-idempotent: false
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: caseId
          in: path
          required: true
          description: Positive numeric case identifier.
          schema:
            type: integer
            format: int64
            minimum: 1
        - name: status
          in: query
          required: false
          description: Repeat to include multiple effect states.
          schema:
            type: string
        - name: effectType
          in: query
          required: false
          description: Repeat to include multiple effect types.
          schema:
            type: string
        - name: triggerType
          in: query
          required: false
          description: Exact trigger type.
          schema:
            type: string
        - name: createdFrom
          in: query
          required: false
          description: Inclusive timestamp lower bound.
          schema:
            type: string
            format: date-time
        - name: createdTo
          in: query
          required: false
          description: Exclusive timestamp upper bound.
          schema:
            type: string
            format: date-time
        - name: limit
          in: query
          required: false
          description: Maximum rows to return.
          schema:
            type: integer
            minimum: 1
            maximum: 200
            default: 50
        - name: cursor
          in: query
          required: false
          description: Opaque newest-first pagination cursor.
          schema:
            type: string
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - items
                  - nextCursor
                  - hasMore
                properties:
                  items:
                    type: array
                    items:
                      type: object
                      required:
                        - effectRef
                        - caseId
                        - effectType
                        - triggerType
                        - status
                        - attemptCount
                        - createdAt
                        - completedAt
                      properties:
                        effectRef:
                          type: string
                        caseId:
                          type: integer
                          description: Stable opaque servicing case identifier.
                        effectType:
                          type: string
                        triggerType:
                          type: string
                        status:
                          type: string
                          description: Current normalized lifecycle state.
                        attemptCount:
                          type: integer
                        createdAt:
                          type: string
                          format: date-time
                        completedAt:
                          type: string
                          format: date-time
                  nextCursor:
                    type: string
                  hasMore:
                    type: boolean
              example:
                items:
                  - effectRef: effect-cancel-autopay-1001-1
                    caseId: 1001
                    effectType: CANCEL_AUTOPAY
                    triggerType: LMS_EVENT
                    status: COMPLETED
                    attemptCount: 1
                    createdAt: 2026-07-25T18:30:00Z
                    completedAt: 2026-07-25T18:30:02Z
                nextCursor: null
                hasMore: false
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
  /v1/servicing/cases/{caseId}/effects/{effectRef}:
    get:
      tags:
        - Case effects
      operationId: getCaseEffect
      summary: Retrieve a case effect
      description: Returns one typed effect, its trigger, attempts, status, timestamps, and redacted result or failure references.
      x-permission: READ_SERVICING_CASE
      x-idempotent: false
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: caseId
          in: path
          required: true
          description: Positive numeric case identifier.
          schema:
            type: integer
            format: int64
            minimum: 1
        - name: effectRef
          in: path
          required: true
          description: Stable opaque effectRef identifier.
          schema:
            type: string
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - effectRef
                  - caseId
                  - effectType
                  - triggerType
                  - status
                  - attemptCount
                  - createdAt
                  - completedAt
                properties:
                  effectRef:
                    type: string
                  caseId:
                    type: integer
                    description: Stable opaque servicing case identifier.
                  effectType:
                    type: string
                  triggerType:
                    type: string
                  status:
                    type: string
                    description: Current normalized lifecycle state.
                  attemptCount:
                    type: integer
                  createdAt:
                    type: string
                    format: date-time
                  completedAt:
                    type: string
                    format: date-time
              example:
                effectRef: effect-cancel-autopay-1001-1
                caseId: 1001
                effectType: CANCEL_AUTOPAY
                triggerType: LMS_EVENT
                status: COMPLETED
                attemptCount: 1
                createdAt: 2026-07-25T18:30:00Z
                completedAt: 2026-07-25T18:30:02Z
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
    post:
      tags:
        - Case effects
      operationId: retryCaseEffect
      summary: Retry a failed case effect
      description: Returns a terminal FAILED effect to PENDING; the workflow executor performs the same typed operation.
        Requires command=retry.
      x-permission: RETRY_SERVICING_CASE_EFFECT
      x-idempotent: true
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: caseId
          in: path
          required: true
          description: Positive numeric case identifier.
          schema:
            type: integer
            format: int64
            minimum: 1
        - name: effectRef
          in: path
          required: true
          description: Stable opaque effectRef identifier.
          schema:
            type: string
        - name: command
          in: query
          required: true
          description: The only supported command variant.
          schema:
            type: string
            enum:
              - retry
        - name: Idempotency-Key
          in: header
          required: false
          description: Optional replay key for this logical mutation. Omission creates a fresh server-owned key for this attempt;
            blank, repeated, or longer-than-50-character values are rejected.
          schema:
            type: string
            minLength: 1
            maxLength: 50
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - effectRef
                  - status
                  - resourceId
                properties:
                  effectRef:
                    type: string
                  status:
                    type: string
                    description: Current normalized lifecycle state.
                  resourceId:
                    type: integer
              example:
                effectRef: effect-cancel-autopay-1001-1
                status: PENDING
                resourceId: 1001
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
        "409":
          $ref: "#/components/responses/Servicing409Error"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - reason
              properties:
                reason:
                  type: string
              example:
                reason: The transient downstream failure has been resolved.
            example:
              reason: The transient downstream failure has been resolved.
  /v1/servicing/ai/outputs/{outputId}:
    get:
      tags:
        - AI governance
      operationId: getServicingAiOutput
      summary: Retrieve an AI output for review
      description: Returns reviewable output state, the proposed content, review evidence and reviewer identity once reviewed,
        and registered session provenance without prompts, model identifiers, secrets, or deployment configuration.
      x-permission: REVIEW_SERVICING_AI_OUTPUT
      x-idempotent: false
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: outputId
          in: path
          required: true
          description: Positive numeric output identifier.
          schema:
            type: integer
            format: int64
            minimum: 1
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - outputId
                  - outputType
                  - status
                  - confidence
                  - groundingStatus
                  - reviewEvidenceIds
                  - proposedContent
                  - createdAt
                  - session
                properties:
                  outputId:
                    type: integer
                  outputType:
                    type: string
                  status:
                    type: string
                    description: Current normalized lifecycle state.
                  confidence:
                    type: number
                  groundingStatus:
                    type: string
                  reviewEvidenceIds:
                    type: array
                    items:
                      type: object
                  proposedContent:
                    type: object
                    required:
                      - summary
                    properties:
                      summary:
                        type: string
                  createdAt:
                    type: string
                    format: date-time
                  session:
                    type: object
                    required:
                      - aiSessionId
                      - workerCode
                      - adapterCode
                      - contractVersion
                      - objective
                      - autonomyLevel
                      - status
                      - caseId
                      - runtimeVersion
                      - policyVersion
                      - workPacketVersion
                    properties:
                      aiSessionId:
                        type: integer
                      workerCode:
                        type: string
                      adapterCode:
                        type: string
                      contractVersion:
                        type: string
                      objective:
                        type: string
                      autonomyLevel:
                        type: string
                      status:
                        type: string
                        description: Current normalized lifecycle state.
                      caseId:
                        type: integer
                        description: Stable opaque servicing case identifier.
                      runtimeVersion:
                        type: string
                      policyVersion:
                        type: string
                      workPacketVersion:
                        type: string
              example:
                outputId: 9001
                outputType: CASE_SUMMARY
                status: PENDING_REVIEW
                confidence: 0.92
                groundingStatus: GROUNDED
                reviewEvidenceIds: []
                proposedContent:
                  summary: Customer missed the June payment; no active bankruptcy restriction.
                createdAt: 2026-07-25T18:30:00Z
                session:
                  aiSessionId: 9501
                  workerCode: COLLECTIONS_ASSISTANT
                  adapterCode: STUB_AI_V1
                  contractVersion: "1.0"
                  objective: SUMMARIZE_CASE
                  autonomyLevel: A2
                  status: COMPLETED
                  caseId: 1001
                  runtimeVersion: runtime-2026.07
                  policyVersion: policy-12
                  workPacketVersion: packet-v1
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
  /v1/servicing/ai/outputs/{outputId}/review:
    post:
      tags:
        - AI governance
      operationId: reviewServicingAiOutput
      summary: Review an AI output
      description: Accepts, edits, rejects, ignores, or escalates a grounded output with retained review evidence.
      x-permission: REVIEW_SERVICING_AI_OUTPUT
      x-idempotent: true
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: outputId
          in: path
          required: true
          description: Positive numeric output identifier.
          schema:
            type: integer
            format: int64
            minimum: 1
        - name: Idempotency-Key
          in: header
          required: false
          description: Optional replay key for this logical mutation. Omission creates a fresh server-owned key for this attempt;
            blank, repeated, or longer-than-50-character values are rejected.
          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:
                      - status
                      - reviewOutcome
                    properties:
                      status:
                        type: string
                        description: Current normalized lifecycle state.
                      reviewOutcome:
                        type: string
              example:
                resourceId: 9001
                changes:
                  status: REVIEWED
                  reviewOutcome: EDITED
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
        "409":
          $ref: "#/components/responses/Servicing409Error"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - reviewOutcome
              properties:
                reviewOutcome:
                  type: string
                finalContent:
                  type: string
                reason:
                  type: string
                evidenceIds:
                  type: array
                  description: Evidence records supporting the request.
                  items:
                    type: integer
              example:
                reviewOutcome: EDITED
                finalContent: Customer missed the June payment and has no active bankruptcy restriction.
                reason: Removed unsupported speculation.
                evidenceIds:
                  - 8801
            example:
              reviewOutcome: EDITED
              finalContent: Customer missed the June payment and has no active bankruptcy restriction.
              reason: Removed unsupported speculation.
              evidenceIds:
                - 8801
  /v1/servicing/admin/ai-suppressions:
    post:
      tags:
        - AI governance
      operationId: setAiSuppression
      summary: Set or restore AI suppression
      description: Suppresses or restores AI dispatch by a closed scope; new and in-flight work rechecks current suppression.
      x-permission: ADMIN_SERVICING_AI
      x-idempotent: true
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: Idempotency-Key
          in: header
          required: false
          description: Optional replay key for this logical mutation. Omission creates a fresh server-owned key for this attempt;
            blank, repeated, or longer-than-50-character values are rejected.
          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:
                      - state
                      - scopeType
                      - scopeRef
                    properties:
                      state:
                        type: string
                      scopeType:
                        type: string
                      scopeRef:
                        type: string
              example:
                resourceId: 9101
                changes:
                  state: SUPPRESSED
                  scopeType: QUEUE
                  scopeRef: COLLECTIONS
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
        "409":
          $ref: "#/components/responses/Servicing409Error"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - scopeType
                - state
                - reason
              properties:
                scopeType:
                  type: string
                scopeRef:
                  type: string
                state:
                  type: string
                reason:
                  type: string
              example:
                scopeType: QUEUE
                scopeRef: COLLECTIONS
                state: SUPPRESSED
                reason: Pause AI dispatch during incident review.
            example:
              scopeType: QUEUE
              scopeRef: COLLECTIONS
              state: SUPPRESSED
              reason: Pause AI dispatch during incident review.
  /v1/servicing/voice-dispatches:
    post:
      tags:
        - Voice
      operationId: createVoiceDispatch
      summary: Dispatch an outbound AI voice call
      description: Locks eligible work, runs the pre-dial gate, selects a registered worker, and emits a bounded grounded
        dispatch packet.
      x-permission: SEND_SERVICING_INTERACTION
      x-idempotent: true
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: Idempotency-Key
          in: header
          required: false
          description: Optional replay key for this logical mutation. Omission creates a fresh server-owned key for this attempt;
            blank, repeated, or longer-than-50-character values are rejected.
          schema:
            type: string
            minLength: 1
            maxLength: 50
      responses:
        "201":
          description: Created.
          content:
            application/json:
              schema:
                type: object
                required:
                  - dispatchId
                  - status
                  - taskId
                  - resourceId
                properties:
                  dispatchId:
                    type: integer
                  status:
                    type: string
                    description: Current normalized lifecycle state.
                  taskId:
                    type: integer
                  resourceId:
                    type: integer
              example:
                dispatchId: 731
                status: AUTHORIZED
                taskId: 2001
                resourceId: 731
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
        "409":
          $ref: "#/components/responses/Servicing409Error"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - taskId
                - loanRef
                - contactPointRef
                - objective
                - reasonCode
              properties:
                taskId:
                  type: integer
                loanRef:
                  type: string
                contactPointRef:
                  type: string
                objective:
                  type: string
                reasonCode:
                  type: string
                  description: Configured structured reason code.
                requestedDialAt:
                  type: string
                  format: date-time
              example:
                taskId: 2001
                loanRef: "456"
                contactPointRef: phone-1
                objective: COLLECT_MISSED_PAYMENT
                reasonCode: COLLECTIONS_FOLLOW_UP
                requestedDialAt: 2026-07-25T19:00:00-07:00
            example:
              taskId: 2001
              loanRef: "456"
              contactPointRef: phone-1
              objective: COLLECT_MISSED_PAYMENT
              reasonCode: COLLECTIONS_FOLLOW_UP
              requestedDialAt: 2026-07-25T19:00:00-07:00
  /v1/servicing/case-types:
    get:
      tags:
        - Cases
      operationId: listCaseTypes
      summary: List enabled case types
      description: Returns the presentation-safe enabled case types, reasons, routing defaults, and current field definitions
        needed by case creation.
      x-permission: READ_SERVICING_CASE
      x-idempotent: false
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - items
                properties:
                  items:
                    type: array
                    items:
                      type: object
                      required:
                        - caseTypeCode
                        - displayName
                        - defaultPriority
                        - serviceLevelMinutes
                        - defaultQueueCode
                        - reasons
                        - fieldDefinitions
                      properties:
                        caseTypeCode:
                          type: string
                        displayName:
                          type: string
                        defaultPriority:
                          type: string
                        serviceLevelMinutes:
                          type: integer
                        defaultQueueCode:
                          type: string
                        reasons:
                          type: array
                          items:
                            type: object
                            required:
                              - reasonCode
                              - displayName
                              - handlingMode
                            properties:
                              reasonCode:
                                type: string
                                description: Configured structured reason code.
                              displayName:
                                type: string
                              handlingMode:
                                type: string
                        fieldDefinitions:
                          type: object
                          required:
                            - sections
                          properties:
                            sections:
                              type: array
                              items:
                                type: object
              example:
                items:
                  - caseTypeCode: COLLECTIONS
                    displayName: Collections
                    defaultPriority: NORMAL
                    serviceLevelMinutes: 1440
                    defaultQueueCode: COLLECTIONS
                    reasons:
                      - reasonCode: DELINQUENCY_SIGNAL
                        displayName: Delinquency signal
                        handlingMode: WORKFLOW
                    fieldDefinitions:
                      sections: []
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
  /v1/servicing/reports/workforce:
    get:
      tags:
        - Servicing reports
      operationId: getWorkforceReport
      summary: Read the workforce report
      description: Returns bounded queue or worker aggregates and canonical drill-through links to base task and case collections.
      x-permission: READ_SERVICING_REPORTS
      x-idempotent: false
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: dimension
          in: query
          required: false
          description: Aggregate dimension.
          schema:
            type: string
            enum:
              - QUEUE
              - WORKER
            default: QUEUE
        - name: queueCode
          in: query
          required: false
          description: Exact queue code.
          schema:
            type: string
        - name: worker
          in: query
          required: false
          description: Exact worker ID or code.
          schema:
            type: string
        - name: workerKind
          in: query
          required: false
          description: Worker kind.
          schema:
            type: string
        - name: presenceState
          in: query
          required: false
          description: Presence state.
          schema:
            type: string
        - name: channel
          in: query
          required: false
          description: Available channel.
          schema:
            type: string
        - name: permittedTaskType
          in: query
          required: false
          description: Eligible task type.
          schema:
            type: string
        - name: caseTypeCode
          in: query
          required: false
          description: Owning case type.
          schema:
            type: string
        - name: staleAccepted
          in: query
          required: false
          description: Filter stale accepted work.
          schema:
            type: boolean
        - name: limit
          in: query
          required: false
          description: Maximum rows to return; defaults to 50.
          schema:
            type: integer
            minimum: 1
            maximum: 200
            default: 50
        - name: offset
          in: query
          required: false
          description: Zero-based row offset; defaults to 0.
          schema:
            type: integer
            minimum: 0
            default: 0
        - name: sort
          in: query
          required: false
          description: Allowlisted sort field for this collection.
          schema:
            type: string
        - name: order
          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:
                  - asOf
                  - effectiveQuery
                  - dimension
                  - summary
                  - rows
                  - returnedCount
                  - hasMore
                properties:
                  asOf:
                    type: string
                    format: date-time
                    description: Time at which the source says the fact was true.
                  effectiveQuery:
                    type: object
                    required:
                      - limit
                      - offset
                    properties:
                      limit:
                        type: integer
                      offset:
                        type: integer
                  dimension:
                    type: string
                  summary:
                    type: object
                    required:
                      - openTaskCount
                      - activeTaskCount
                      - staleAcceptedTaskCount
                      - overdueTaskCount
                      - slaBreachedTaskCount
                      - openCaseCount
                      - availableWorkerCapacity
                    properties:
                      openTaskCount:
                        type: integer
                      activeTaskCount:
                        type: integer
                      staleAcceptedTaskCount:
                        type: integer
                      overdueTaskCount:
                        type: integer
                      slaBreachedTaskCount:
                        type: integer
                      openCaseCount:
                        type: integer
                      availableWorkerCapacity:
                        type: integer
                  rows:
                    type: array
                    items:
                      type: object
                      required:
                        - queueCode
                        - openTaskCount
                        - activeTaskCount
                        - overdueTaskCount
                        - slaBreachedTaskCount
                        - oldestTaskAgeMinutes
                        - eligibleWorkerCapacity
                        - availableWorkerCount
                        - drillThrough
                      properties:
                        queueCode:
                          type: string
                        openTaskCount:
                          type: integer
                        activeTaskCount:
                          type: integer
                        overdueTaskCount:
                          type: integer
                        slaBreachedTaskCount:
                          type: integer
                        oldestTaskAgeMinutes:
                          type: integer
                        eligibleWorkerCapacity:
                          type: integer
                        availableWorkerCount:
                          type: integer
                        drillThrough:
                          type: string
                  returnedCount:
                    type: integer
                  hasMore:
                    type: boolean
              example:
                asOf: 2026-07-25T18:30:00Z
                effectiveQuery:
                  limit: 50
                  offset: 0
                dimension: QUEUE
                summary:
                  openTaskCount: 18
                  activeTaskCount: 7
                  staleAcceptedTaskCount: 1
                  overdueTaskCount: 2
                  slaBreachedTaskCount: 1
                  openCaseCount: 42
                  availableWorkerCapacity: 21
                rows:
                  - queueCode: COLLECTIONS
                    openTaskCount: 18
                    activeTaskCount: 7
                    overdueTaskCount: 2
                    slaBreachedTaskCount: 1
                    oldestTaskAgeMinutes: 91
                    eligibleWorkerCapacity: 28
                    availableWorkerCount: 4
                    drillThrough: /v1/servicing/tasks?queueCode=COLLECTIONS
                returnedCount: 1
                hasMore: false
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
  /v1/servicing/reports/collections:
    get:
      tags:
        - Servicing reports
      operationId: getCollectionsReport
      summary: Read the collections report
      description: Returns bounded collection-case projections from current LMS facts and servicing work state.
      x-permission: READ_SERVICING_REPORTS
      x-idempotent: false
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: delinquencyBucket
          in: query
          required: false
          description: Exact delinquency bucket.
          schema:
            type: string
        - name: daysOverdueMin
          in: query
          required: false
          description: Minimum days overdue.
          schema:
            type: integer
        - name: daysOverdueMax
          in: query
          required: false
          description: Maximum days overdue.
          schema:
            type: integer
        - name: overdueAmountMin
          in: query
          required: false
          description: Minimum overdue amount.
          schema:
            type: number
        - name: overdueAmountMax
          in: query
          required: false
          description: Maximum overdue amount.
          schema:
            type: number
        - name: currency
          in: query
          required: false
          description: ISO currency required with amount bounds.
          schema:
            type: string
        - name: promiseState
          in: query
          required: false
          description: Exact promise state.
          schema:
            type: string
        - name: contactBlocked
          in: query
          required: false
          description: Filter by contact blocking.
          schema:
            type: boolean
        - name: nextPermittedContactFrom
          in: query
          required: false
          description: Inclusive timestamp lower bound.
          schema:
            type: string
            format: date-time
        - name: nextPermittedContactTo
          in: query
          required: false
          description: Exclusive timestamp upper bound.
          schema:
            type: string
            format: date-time
        - name: limit
          in: query
          required: false
          description: Maximum rows to return; defaults to 50.
          schema:
            type: integer
            minimum: 1
            maximum: 200
            default: 50
        - name: offset
          in: query
          required: false
          description: Zero-based row offset; defaults to 0.
          schema:
            type: integer
            minimum: 0
            default: 0
        - name: sort
          in: query
          required: false
          description: Allowlisted sort field for this collection.
          schema:
            type: string
        - name: order
          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:
                  - asOf
                  - effectiveQuery
                  - rows
                  - returnedCount
                  - hasMore
                properties:
                  asOf:
                    type: string
                    format: date-time
                    description: Time at which the source says the fact was true.
                  effectiveQuery:
                    type: object
                    required:
                      - limit
                      - offset
                    properties:
                      limit:
                        type: integer
                      offset:
                        type: integer
                  rows:
                    type: array
                    items:
                      type: object
                      required:
                        - caseId
                        - customerRef
                        - loanRef
                        - priority
                        - promiseState
                        - financialFactsSource
                        - daysOverdue
                        - delinquencyBucket
                        - overdueAmount
                        - currency
                        - contactIntensity
                        - remainingContactCapacity
                        - lastContactAttemptAt
                        - nextPermittedContactAt
                        - protectiveStateActive
                        - contactBlocked
                      properties:
                        caseId:
                          type: integer
                          description: Stable opaque servicing case identifier.
                        customerRef:
                          type: string
                        loanRef:
                          type: string
                        priority:
                          type: string
                        promiseState:
                          type: string
                        financialFactsSource:
                          type: string
                        daysOverdue:
                          type: integer
                        delinquencyBucket:
                          type: string
                        overdueAmount:
                          type: number
                        currency:
                          type: string
                          pattern: ^[A-Z]{3}$
                          description: ISO 4217 currency code.
                        contactIntensity:
                          type: integer
                        remainingContactCapacity:
                          type: integer
                        lastContactAttemptAt:
                          type: string
                          format: date-time
                        nextPermittedContactAt:
                          type: string
                          format: date-time
                        protectiveStateActive:
                          type: boolean
                        contactBlocked:
                          type: boolean
                  returnedCount:
                    type: integer
                  hasMore:
                    type: boolean
              example:
                asOf: 2026-07-25T18:30:00Z
                effectiveQuery:
                  limit: 50
                  offset: 0
                rows:
                  - caseId: 1001
                    customerRef: "123"
                    loanRef: "456"
                    priority: HIGH
                    promiseState: ACTIVE
                    financialFactsSource: LMS
                    daysOverdue: 22
                    delinquencyBucket: DPD_1_29
                    overdueAmount: 517.14
                    currency: USD
                    contactIntensity: 2
                    remainingContactCapacity: 5
                    lastContactAttemptAt: 2026-07-24T21:04:00Z
                    nextPermittedContactAt: 2026-07-26T15:00:00Z
                    protectiveStateActive: false
                    contactBlocked: false
                returnedCount: 1
                hasMore: false
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
  /v1/servicing/reports/interactions/exceptions:
    get:
      tags:
        - Servicing reports
      operationId: getInteractionExceptionsReport
      summary: Read interaction exceptions
      description: Returns missed, unmatched, failed, or classification-required channel work.
      x-permission: READ_SERVICING_REPORTS
      x-idempotent: false
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: channel
          in: query
          required: false
          description: Exact channel.
          schema:
            type: string
        - name: status
          in: query
          required: false
          description: Repeat to include multiple states.
          schema:
            type: string
        - name: borrowerMatched
          in: query
          required: false
          description: Filter by customer match.
          schema:
            type: boolean
        - name: caseLinked
          in: query
          required: false
          description: Filter by case link.
          schema:
            type: boolean
        - name: queueCode
          in: query
          required: false
          description: Exact queue.
          schema:
            type: string
        - name: assignedTo
          in: query
          required: false
          description: Worker ID, me, or unassigned.
          schema:
            type: string
        - name: sensitive
          in: query
          required: false
          description: Filter by sensitivity.
          schema:
            type: boolean
        - name: createdFrom
          in: query
          required: false
          description: Inclusive timestamp lower bound.
          schema:
            type: string
            format: date-time
        - name: createdTo
          in: query
          required: false
          description: Exclusive timestamp upper bound.
          schema:
            type: string
            format: date-time
        - name: limit
          in: query
          required: false
          description: Maximum rows to return; defaults to 50.
          schema:
            type: integer
            minimum: 1
            maximum: 200
            default: 50
        - name: offset
          in: query
          required: false
          description: Zero-based row offset; defaults to 0.
          schema:
            type: integer
            minimum: 0
            default: 0
        - name: sort
          in: query
          required: false
          description: Allowlisted sort field for this collection.
          schema:
            type: string
        - name: order
          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:
                  - asOf
                  - effectiveQuery
                  - rows
                  - returnedCount
                  - hasMore
                properties:
                  asOf:
                    type: string
                    format: date-time
                    description: Time at which the source says the fact was true.
                  effectiveQuery:
                    type: object
                    required:
                      - limit
                      - offset
                    properties:
                      limit:
                        type: integer
                      offset:
                        type: integer
                  rows:
                    type: array
                    items:
                      type: object
                      required:
                        - interactionId
                        - channel
                        - direction
                        - status
                        - borrowerMatched
                        - caseLinked
                        - priority
                        - sensitive
                        - createdAt
                        - ageMinutes
                      properties:
                        interactionId:
                          type: integer
                        channel:
                          type: string
                        direction:
                          type: string
                        status:
                          type: string
                          description: Current normalized lifecycle state.
                        borrowerMatched:
                          type: boolean
                        caseLinked:
                          type: boolean
                        priority:
                          type: string
                        sensitive:
                          type: boolean
                        createdAt:
                          type: string
                          format: date-time
                        ageMinutes:
                          type: integer
                  returnedCount:
                    type: integer
                  hasMore:
                    type: boolean
              example:
                asOf: 2026-07-25T18:30:00Z
                effectiveQuery:
                  limit: 50
                  offset: 0
                rows:
                  - interactionId: 3005
                    channel: PHONE
                    direction: INBOUND
                    status: FAILED
                    borrowerMatched: false
                    caseLinked: false
                    priority: HIGH
                    sensitive: false
                    createdAt: 2026-07-25T18:16:00Z
                    ageMinutes: 14
                returnedCount: 1
                hasMore: false
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
  /v1/servicing/reports/compliance:
    get:
      tags:
        - Servicing reports
      operationId: getComplianceReport
      summary: Read the compliance report
      description: Returns bounded decision outcomes, hard stops, rules, regimes, channels, and proposed actions.
      x-permission: READ_SERVICING_REPORTS
      x-idempotent: false
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: outcome
          in: query
          required: false
          description: Exact compliance outcome.
          schema:
            type: string
        - name: hardStop
          in: query
          required: false
          description: Filter hard-stop decisions.
          schema:
            type: boolean
        - name: regime
          in: query
          required: false
          description: Exact configured regime.
          schema:
            type: string
        - name: ruleCode
          in: query
          required: false
          description: Exact rule code.
          schema:
            type: string
        - name: channel
          in: query
          required: false
          description: Exact channel.
          schema:
            type: string
        - name: proposedAction
          in: query
          required: false
          description: Exact proposed action.
          schema:
            type: string
        - name: evaluatedFrom
          in: query
          required: false
          description: Inclusive timestamp lower bound.
          schema:
            type: string
            format: date-time
        - name: evaluatedTo
          in: query
          required: false
          description: Exclusive timestamp upper bound.
          schema:
            type: string
            format: date-time
        - name: limit
          in: query
          required: false
          description: Maximum rows to return; defaults to 50.
          schema:
            type: integer
            minimum: 1
            maximum: 200
            default: 50
        - name: offset
          in: query
          required: false
          description: Zero-based row offset; defaults to 0.
          schema:
            type: integer
            minimum: 0
            default: 0
        - name: sort
          in: query
          required: false
          description: Allowlisted sort field for this collection.
          schema:
            type: string
        - name: order
          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:
                  - asOf
                  - effectiveQuery
                  - rows
                  - returnedCount
                  - hasMore
                properties:
                  asOf:
                    type: string
                    format: date-time
                    description: Time at which the source says the fact was true.
                  effectiveQuery:
                    type: object
                    required:
                      - limit
                      - offset
                    properties:
                      limit:
                        type: integer
                      offset:
                        type: integer
                  rows:
                    type: array
                    items:
                      type: object
                      required:
                        - decisionId
                        - evaluatedAt
                        - customerRef
                        - caseId
                        - proposedAction
                        - channel
                        - outcome
                        - hardStop
                        - rules
                      properties:
                        decisionId:
                          type: integer
                        evaluatedAt:
                          type: string
                          format: date-time
                        customerRef:
                          type: string
                        caseId:
                          type: integer
                          description: Stable opaque servicing case identifier.
                        proposedAction:
                          type: string
                        channel:
                          type: string
                        outcome:
                          type: string
                        hardStop:
                          type: boolean
                        rules:
                          type: array
                          items:
                            type: object
                            required:
                              - ruleCode
                              - regime
                              - outcome
                            properties:
                              ruleCode:
                                type: string
                              regime:
                                type: string
                              outcome:
                                type: string
                  returnedCount:
                    type: integer
                  hasMore:
                    type: boolean
              example:
                asOf: 2026-07-25T18:30:00Z
                effectiveQuery:
                  limit: 50
                  offset: 0
                rows:
                  - decisionId: 6117
                    evaluatedAt: 2026-07-25T18:30:00Z
                    customerRef: "123"
                    caseId: 1001
                    proposedAction: OUTBOUND_CONTACT
                    channel: PHONE
                    outcome: ALLOWED
                    hardStop: false
                    rules:
                      - ruleCode: CONTACT_WINDOW_CA
                        regime: REG_F
                        outcome: ALLOWED
                returnedCount: 1
                hasMore: false
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
  /v1/servicing/reports/ai-quality:
    get:
      tags:
        - Servicing reports
      operationId: getAiQualityReport
      summary: Read the AI-quality report
      description: Returns retained output, grounding, runtime, and human-review quality projections.
      x-permission: READ_SERVICING_REPORTS
      x-idempotent: false
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: workerCode
          in: query
          required: false
          description: Exact registered worker code.
          schema:
            type: string
        - name: adapterCode
          in: query
          required: false
          description: Exact adapter code.
          schema:
            type: string
        - name: outputType
          in: query
          required: false
          description: Exact output type.
          schema:
            type: string
        - name: outputStatus
          in: query
          required: false
          description: Exact output state.
          schema:
            type: string
        - name: runtimeVersion
          in: query
          required: false
          description: Exact worker-reported runtime version.
          schema:
            type: string
        - name: reviewer
          in: query
          required: false
          description: Reviewer ID or me.
          schema:
            type: string
        - name: reviewedFrom
          in: query
          required: false
          description: Inclusive timestamp lower bound.
          schema:
            type: string
            format: date-time
        - name: reviewedTo
          in: query
          required: false
          description: Exclusive timestamp upper bound.
          schema:
            type: string
            format: date-time
        - name: limit
          in: query
          required: false
          description: Maximum rows to return; defaults to 50.
          schema:
            type: integer
            minimum: 1
            maximum: 200
            default: 50
        - name: offset
          in: query
          required: false
          description: Zero-based row offset; defaults to 0.
          schema:
            type: integer
            minimum: 0
            default: 0
        - name: sort
          in: query
          required: false
          description: Allowlisted sort field for this collection.
          schema:
            type: string
        - name: order
          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:
                  - asOf
                  - effectiveQuery
                  - rows
                  - returnedCount
                  - hasMore
                properties:
                  asOf:
                    type: string
                    format: date-time
                    description: Time at which the source says the fact was true.
                  effectiveQuery:
                    type: object
                    required:
                      - limit
                      - offset
                    properties:
                      limit:
                        type: integer
                      offset:
                        type: integer
                  rows:
                    type: array
                    items:
                      type: object
                      required:
                        - aiSessionId
                        - workerCode
                        - adapterCode
                        - contractVersion
                        - objective
                        - autonomyLevel
                        - runtimeVersion
                        - policyVersion
                        - workPacketVersion
                        - sessionStatus
                        - startedAt
                        - caseId
                        - outputId
                        - outputType
                        - outputStatus
                        - confidence
                        - groundingStatus
                        - reviewerWorkerId
                        - reviewerWorkerCode
                        - reviewedAt
                      properties:
                        aiSessionId:
                          type: integer
                        workerCode:
                          type: string
                        adapterCode:
                          type: string
                        contractVersion:
                          type: string
                        objective:
                          type: string
                        autonomyLevel:
                          type: string
                        runtimeVersion:
                          type: string
                        policyVersion:
                          type: string
                        workPacketVersion:
                          type: string
                        sessionStatus:
                          type: string
                        startedAt:
                          type: string
                          format: date-time
                        caseId:
                          type: integer
                          description: Stable opaque servicing case identifier.
                        outputId:
                          type: integer
                        outputType:
                          type: string
                        outputStatus:
                          type: string
                        confidence:
                          type: number
                        groundingStatus:
                          type: string
                        reviewerWorkerId:
                          type: integer
                        reviewerWorkerCode:
                          type: string
                        reviewedAt:
                          type: string
                          format: date-time
                  returnedCount:
                    type: integer
                  hasMore:
                    type: boolean
              example:
                asOf: 2026-07-25T18:30:00Z
                effectiveQuery:
                  limit: 50
                  offset: 0
                rows:
                  - aiSessionId: 9501
                    workerCode: COLLECTIONS_ASSISTANT
                    adapterCode: STUB_AI_V1
                    contractVersion: "1.0"
                    objective: SUMMARIZE_CASE
                    autonomyLevel: A2
                    runtimeVersion: runtime-2026.07
                    policyVersion: policy-12
                    workPacketVersion: packet-v1
                    sessionStatus: COMPLETED
                    startedAt: 2026-07-25T18:20:00Z
                    caseId: 1001
                    outputId: 9001
                    outputType: CASE_SUMMARY
                    outputStatus: REVIEWED
                    confidence: 0.92
                    groundingStatus: GROUNDED
                    reviewerWorkerId: 4101
                    reviewerWorkerCode: MARIA_AGENT
                    reviewedAt: 2026-07-25T18:35:00Z
                returnedCount: 1
                hasMore: false
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
  /v1/servicing/reports/reconciliation:
    get:
      tags:
        - Servicing reports
      operationId: getServicingReconciliationReport
      summary: Read the servicing reconciliation report
      description: Returns current servicing-to-LMS drift classifications and resolution state without exposing implementation
        tables.
      x-permission: READ_SERVICING_REPORTS
      x-idempotent: false
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: driftId
          in: query
          required: false
          description: Exact drift record ID.
          schema:
            type: integer
        - name: driftType
          in: query
          required: false
          description: Exact drift classification.
          schema:
            type: string
        - name: status
          in: query
          required: false
          description: Repeat to include multiple states.
          schema:
            type: string
        - name: objectType
          in: query
          required: false
          description: Exact affected object type.
          schema:
            type: string
        - name: detectedFrom
          in: query
          required: false
          description: Inclusive timestamp lower bound.
          schema:
            type: string
            format: date-time
        - name: detectedTo
          in: query
          required: false
          description: Exclusive timestamp upper bound.
          schema:
            type: string
            format: date-time
        - name: priority
          in: query
          required: false
          description: Repeat to include multiple priorities.
          schema:
            type: string
        - name: limit
          in: query
          required: false
          description: Maximum rows to return; defaults to 50.
          schema:
            type: integer
            minimum: 1
            maximum: 200
            default: 50
        - name: offset
          in: query
          required: false
          description: Zero-based row offset; defaults to 0.
          schema:
            type: integer
            minimum: 0
            default: 0
        - name: sort
          in: query
          required: false
          description: Allowlisted sort field for this collection.
          schema:
            type: string
        - name: order
          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:
                  - asOf
                  - effectiveQuery
                  - rows
                  - returnedCount
                  - hasMore
                properties:
                  asOf:
                    type: string
                    format: date-time
                    description: Time at which the source says the fact was true.
                  effectiveQuery:
                    type: object
                    required:
                      - limit
                      - offset
                    properties:
                      limit:
                        type: integer
                      offset:
                        type: integer
                  rows:
                    type: array
                    items:
                      type: object
                      required:
                        - driftId
                        - driftType
                        - objectType
                        - objectRef
                        - customerRef
                        - status
                        - priority
                        - reviewTaskId
                        - detectedAt
                      properties:
                        driftId:
                          type: integer
                        driftType:
                          type: string
                        objectType:
                          type: string
                        objectRef:
                          type: string
                        customerRef:
                          type: string
                        status:
                          type: string
                          description: Current normalized lifecycle state.
                        priority:
                          type: string
                        reviewTaskId:
                          type: integer
                        detectedAt:
                          type: string
                          format: date-time
                  returnedCount:
                    type: integer
                  hasMore:
                    type: boolean
              example:
                asOf: 2026-07-25T18:30:00Z
                effectiveQuery:
                  limit: 50
                  offset: 0
                rows:
                  - driftId: 81
                    driftType: EXPECTED_STATE_MISMATCH
                    objectType: AUTOPAY
                    objectRef: "456"
                    customerRef: "123"
                    status: OPEN
                    priority: HIGH
                    reviewTaskId: 2005
                    detectedAt: 2026-07-25T18:30:00Z
                returnedCount: 1
                hasMore: false
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
  /v1/servicing/reports/investor:
    get:
      tags:
        - Servicing reports
      operationId: listInvestorReports
      summary: List investor reports
      description: "Returns the closed 18-report investor catalog with snapshot provenance. The projection is a curated,
        non-authoritative snapshot: it never reads live servicing or ledger tables, and every response carries its load
        key and source watermark."
      x-permission: READ_REPORT|READ_SERVICING_REPORTS
      x-idempotent: false
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - asOf
                  - periodStart
                  - periodEnd
                  - currency
                  - demo
                  - status
                  - provenance
                  - reports
                  - reportCount
                properties:
                  asOf:
                    type: string
                    format: date-time
                    description: Time at which the source says the fact was true.
                  periodStart:
                    type: string
                  periodEnd:
                    type: string
                  currency:
                    type: string
                    pattern: ^[A-Z]{3}$
                    description: ISO 4217 currency code.
                  demo:
                    type: boolean
                  status:
                    type: string
                    description: Current normalized lifecycle state.
                  provenance:
                    type: object
                    required:
                      - label
                      - loadKey
                      - sourceWatermark
                      - generationMode
                      - nonAuthoritative
                    properties:
                      label:
                        type: string
                      loadKey:
                        type: string
                      sourceWatermark:
                        type: string
                      generationMode:
                        type: string
                      nonAuthoritative:
                        type: boolean
                  reports:
                    type: array
                    items:
                      type: object
                      required:
                        - key
                        - title
                        - category
                        - description
                        - question
                        - cadence
                        - accent
                        - featured
                        - sortOrder
                      properties:
                        key:
                          type: string
                        title:
                          type: string
                        category:
                          type: string
                        description:
                          type: string
                        question:
                          type: string
                        cadence:
                          type: string
                        accent:
                          type: string
                        featured:
                          type: boolean
                        sortOrder:
                          type: integer
                  reportCount:
                    type: integer
              example:
                asOf: 2026-07-25T18:30:00Z
                periodStart: 2025-02-01
                periodEnd: 2026-07-25
                currency: USD
                demo: false
                status: COMPLETE
                provenance:
                  label: Reporting snapshot
                  loadKey: INVESTOR_V1:2026-07-25
                  sourceWatermark: portfolio-v1:2026-07-25
                  generationMode: SNAPSHOT_LOAD
                  nonAuthoritative: true
                reports:
                  - key: executive-pulse
                    title: Executive Pulse
                    category: Executive
                    description: "The one-page operating picture: scale, growth, earnings, credit, liquidity, and execution."
                    question: Is the platform compounding responsibly, and where should leadership look next?
                    cadence: Daily close
                    accent: EMERALD
                    featured: true
                    sortOrder: 1
                  - key: collections-promises
                    title: Collections And Promises
                    category: Credit & Collections
                    description: Case demand, contact activity, promise conversion, promise dollars, and kept rate.
                    question: Is collections work producing credible commitments and realized cash?
                    cadence: Daily close
                    accent: AMBER
                    featured: false
                    sortOrder: 14
                reportCount: 2
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
  /v1/servicing/reports/investor/{reportKey}:
    get:
      tags:
        - Servicing reports
      operationId: getInvestorReport
      summary: Read an investor report
      description: "Returns one curated report from the latest completed snapshot: headline metrics, insights, a trend, a
        breakdown, a supporting table, and the methodology note. The report key must come from the investor catalog;
        delta and share keys are omitted when not supplied."
      x-permission: READ_REPORT|READ_SERVICING_REPORTS
      x-idempotent: false
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: reportKey
          in: path
          required: true
          description: Report key from the investor-report catalog.
          schema:
            type: string
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - asOf
                  - periodStart
                  - periodEnd
                  - currency
                  - demo
                  - status
                  - provenance
                  - key
                  - title
                  - category
                  - description
                  - question
                  - cadence
                  - accent
                  - metrics
                  - insights
                  - trend
                  - breakdown
                  - table
                  - methodology
                properties:
                  asOf:
                    type: string
                    format: date-time
                    description: Time at which the source says the fact was true.
                  periodStart:
                    type: string
                  periodEnd:
                    type: string
                  currency:
                    type: string
                    pattern: ^[A-Z]{3}$
                    description: ISO 4217 currency code.
                  demo:
                    type: boolean
                  status:
                    type: string
                    description: Current normalized lifecycle state.
                  provenance:
                    type: object
                    required:
                      - label
                      - loadKey
                      - sourceWatermark
                      - generationMode
                      - nonAuthoritative
                    properties:
                      label:
                        type: string
                      loadKey:
                        type: string
                      sourceWatermark:
                        type: string
                      generationMode:
                        type: string
                      nonAuthoritative:
                        type: boolean
                  key:
                    type: string
                  title:
                    type: string
                  category:
                    type: string
                  description:
                    type: string
                  question:
                    type: string
                  cadence:
                    type: string
                  accent:
                    type: string
                  metrics:
                    type: array
                    items:
                      type: object
                      required:
                        - key
                        - label
                        - value
                        - format
                        - tone
                        - context
                      properties:
                        key:
                          type: string
                        label:
                          type: string
                        value:
                          type: integer
                        format:
                          type: string
                          format: date-time
                        tone:
                          type: string
                        context:
                          type: string
                          description: Case, system-trigger, or approved-exception context for the action.
                  insights:
                    type: array
                    items:
                      type: object
                      required:
                        - tone
                        - title
                        - body
                      properties:
                        tone:
                          type: string
                        title:
                          type: string
                        body:
                          type: string
                  trend:
                    type: object
                    required:
                      - title
                      - description
                      - format
                      - series
                    properties:
                      title:
                        type: string
                      description:
                        type: string
                      format:
                        type: string
                        format: date-time
                      series:
                        type: array
                        items:
                          type: object
                          required:
                            - key
                            - label
                            - accent
                            - points
                          properties:
                            key:
                              type: string
                            label:
                              type: string
                            accent:
                              type: string
                            points:
                              type: array
                              items:
                                type: object
                                required:
                                  - period
                                  - label
                                  - value
                                properties:
                                  period:
                                    type: string
                                  label:
                                    type: string
                                  value:
                                    type: integer
                  breakdown:
                    type: object
                    required:
                      - title
                      - description
                      - format
                      - items
                    properties:
                      title:
                        type: string
                      description:
                        type: string
                      format:
                        type: string
                        format: date-time
                      items:
                        type: array
                        items:
                          type: object
                          required:
                            - label
                            - value
                            - share
                            - tone
                          properties:
                            label:
                              type: string
                            value:
                              type: integer
                            share:
                              type: number
                            tone:
                              type: string
                  table:
                    type: object
                    required:
                      - title
                      - columns
                      - rows
                    properties:
                      title:
                        type: string
                      columns:
                        type: array
                        items:
                          type: object
                          required:
                            - key
                            - label
                            - format
                          properties:
                            key:
                              type: string
                            label:
                              type: string
                            format:
                              type: string
                              format: date-time
                      rows:
                        type: array
                        items:
                          type: object
                          required:
                            - period
                            - promises
                            - keptRate
                            - promiseAmount
                          properties:
                            period:
                              type: string
                            promises:
                              type: integer
                            keptRate:
                              type: number
                            promiseAmount:
                              type: integer
                  methodology:
                    type: string
              example:
                asOf: 2026-07-25T18:30:00Z
                periodStart: 2025-02-01
                periodEnd: 2026-07-25
                currency: USD
                demo: false
                status: COMPLETE
                provenance:
                  label: Reporting snapshot
                  loadKey: INVESTOR_V1:2026-07-25
                  sourceWatermark: portfolio-v1:2026-07-25
                  generationMode: SNAPSHOT_LOAD
                  nonAuthoritative: true
                key: collections-promises
                title: Collections And Promises
                category: Credit & Collections
                description: Case demand, contact activity, promise conversion, promise dollars, and kept rate.
                question: Is collections work producing credible commitments and realized cash?
                cadence: Daily close
                accent: AMBER
                metrics:
                  - key: openCases
                    label: Open collection cases
                    value: 230
                    format: number
                    tone: neutral
                    context: Active servicing cases requiring work.
                  - key: keptRate
                    label: Promise kept rate
                    value: 82.7068
                    format: percent
                    delta: 0.6755
                    deltaLabel: vs prior month
                    tone: positive
                    context: Promises kept divided by promises created.
                  - key: promiseAmount
                    label: Promise dollars
                    value: 55594
                    format: currency
                    tone: neutral
                    context: Committed amount in the latest month.
                  - key: keptAmount
                    label: Realized promise dollars
                    value: 48510
                    format: currency
                    tone: positive
                    context: Cash realized from kept promises.
                insights:
                  - tone: positive
                    title: Promise quality is improving
                    body: Kept-rate improvement indicates contacts are producing more credible commitments.
                  - tone: neutral
                    title: Commitments and cash stay distinct
                    body: Promise dollars are never counted as collected until the corresponding cash is realized.
                trend:
                  title: Promise conversion
                  description: Promises created and kept over twelve months.
                  format: number
                  series:
                    - key: created
                      label: Created
                      accent: AMBER
                      points:
                        - period: 2026-06-01
                          label: Jun 26
                          value: 128
                        - period: 2026-07-01
                          label: Jul 26
                          value: 133
                    - key: kept
                      label: Kept
                      accent: EMERALD
                      points:
                        - period: 2026-06-01
                          label: Jun 26
                          value: 105
                        - period: 2026-07-01
                          label: Jul 26
                          value: 110
                breakdown:
                  title: Latest contact-channel mix
                  description: Countable servicing contacts by channel.
                  format: number
                  items:
                    - label: Phone
                      value: 453
                      share: 46.0366
                      tone: BLUE
                    - label: Email
                      value: 335
                      share: 34.0447
                      tone: VIOLET
                    - label: SMS
                      value: 197
                      share: 20.0203
                      tone: EMERALD
                table:
                  title: Monthly collections execution
                  columns:
                    - key: period
                      label: Period
                      format: text
                    - key: promises
                      label: Promises
                      format: number
                    - key: keptRate
                      label: Kept rate
                      format: percent
                    - key: promiseAmount
                      label: Promise dollars
                      format: currency
                  rows:
                    - period: Jun 26
                      promises: 128
                      keptRate: 82.0313
                      promiseAmount: 52480
                    - period: Jul 26
                      promises: 133
                      keptRate: 82.7068
                      promiseAmount: 55594
                methodology: Closed monthly servicing aggregates. Kept rate is count-based; dollar kept rate is value-based. Contact
                  counts include only countable servicing attempts.
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
  /v1/servicing/cases/{caseId}/evidence-export:
    get:
      tags:
        - Evidence exports
      operationId: getCaseEvidenceExport
      summary: Export case evidence
      description: Returns an audited JSON examination bundle reconstructed from case decisions, inputs, signals, facts, work,
        interactions, requests, AI provenance, and results.
      x-permission: EXPORT_SERVICING_EVIDENCE
      x-idempotent: false
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: caseId
          in: path
          required: true
          description: Positive numeric case identifier.
          schema:
            type: integer
            format: int64
            minimum: 1
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - subjectType
                  - subjectRef
                  - generatedAt
                  - cases
                  - decisions
                  - interactions
                  - actionRequests
                  - effects
                  - integrity
                properties:
                  subjectType:
                    type: string
                  subjectRef:
                    type: string
                  generatedAt:
                    type: string
                    format: date-time
                  cases:
                    type: array
                    items:
                      type: object
                      required:
                        - caseId
                        - externalCaseRef
                        - customerRef
                        - caseTypeCode
                        - reasonCode
                        - status
                        - priority
                        - ownerQueueCode
                        - serviceLevelDueAt
                        - lastUpdatedAt
                        - sensitive
                      properties:
                        caseId:
                          type: integer
                          description: Stable opaque servicing case identifier.
                        externalCaseRef:
                          type: string
                        customerRef:
                          type: string
                        caseTypeCode:
                          type: string
                        reasonCode:
                          type: string
                          description: Configured structured reason code.
                        status:
                          type: string
                          description: Current normalized lifecycle state.
                        priority:
                          type: string
                        ownerQueueCode:
                          type: string
                        serviceLevelDueAt:
                          type: string
                          format: date-time
                        lastUpdatedAt:
                          type: string
                          format: date-time
                        sensitive:
                          type: boolean
                  decisions:
                    type: array
                    items:
                      type: object
                  interactions:
                    type: array
                    items:
                      type: object
                      required:
                        - interactionId
                        - customerRef
                        - caseId
                        - channel
                        - direction
                        - interactionType
                        - reasonCode
                        - status
                        - verificationState
                        - contentSummary
                        - createdAt
                      properties:
                        interactionId:
                          type: integer
                        customerRef:
                          type: string
                        caseId:
                          type: integer
                          description: Stable opaque servicing case identifier.
                        channel:
                          type: string
                        direction:
                          type: string
                        interactionType:
                          type: string
                        reasonCode:
                          type: string
                          description: Configured structured reason code.
                        status:
                          type: string
                          description: Current normalized lifecycle state.
                        verificationState:
                          type: string
                        contentSummary:
                          type: string
                        createdAt:
                          type: string
                          format: date-time
                  actionRequests:
                    type: array
                    items:
                      type: object
                  effects:
                    type: array
                    items:
                      type: object
                      required:
                        - effectRef
                        - caseId
                        - effectType
                        - triggerType
                        - status
                        - attemptCount
                        - createdAt
                        - completedAt
                      properties:
                        effectRef:
                          type: string
                        caseId:
                          type: integer
                          description: Stable opaque servicing case identifier.
                        effectType:
                          type: string
                        triggerType:
                          type: string
                        status:
                          type: string
                          description: Current normalized lifecycle state.
                        attemptCount:
                          type: integer
                        createdAt:
                          type: string
                          format: date-time
                        completedAt:
                          type: string
                          format: date-time
                  integrity:
                    type: object
                    required:
                      - chainComplete
                    properties:
                      chainComplete:
                        type: boolean
              example:
                subjectType: CASE
                subjectRef: "1001"
                generatedAt: 2026-07-25T18:30:00Z
                cases:
                  - caseId: 1001
                    externalCaseRef: LE-CASE-1001
                    customerRef: "123"
                    caseTypeCode: COLLECTIONS
                    reasonCode: DELINQUENCY_SIGNAL
                    status: OPEN
                    priority: HIGH
                    ownerQueueCode: COLLECTIONS
                    serviceLevelDueAt: 2026-07-26T17:00:00Z
                    lastUpdatedAt: 2026-07-25T18:30:00Z
                    sensitive: false
                decisions: []
                interactions:
                  - interactionId: 3001
                    customerRef: "123"
                    caseId: 1001
                    channel: EMAIL
                    direction: INBOUND
                    interactionType: MESSAGE
                    reasonCode: PAYMENT_QUESTION
                    status: COMPLETED
                    verificationState: NOT_APPLICABLE
                    contentSummary: Customer asks why a payment did not post.
                    createdAt: 2026-07-25T18:30:00Z
                actionRequests: []
                effects:
                  - effectRef: effect-cancel-autopay-1001-1
                    caseId: 1001
                    effectType: CANCEL_AUTOPAY
                    triggerType: LMS_EVENT
                    status: COMPLETED
                    attemptCount: 1
                    createdAt: 2026-07-25T18:30:00Z
                    completedAt: 2026-07-25T18:30:02Z
                integrity:
                  chainComplete: true
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
  /v1/servicing/customers/{customerRef}/evidence-export:
    get:
      tags:
        - Evidence exports
      operationId: getCustomerEvidenceExport
      summary: Export customer servicing evidence
      description: Returns an audited JSON bundle across visible servicing cases for one customer, subject to
        sensitive-content permissions.
      x-permission: EXPORT_SERVICING_EVIDENCE
      x-idempotent: false
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: customerRef
          in: path
          required: true
          description: Stable opaque customerRef identifier.
          schema:
            type: string
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - subjectType
                  - subjectRef
                  - generatedAt
                  - cases
                  - decisions
                  - interactions
                  - actionRequests
                  - effects
                  - integrity
                properties:
                  subjectType:
                    type: string
                  subjectRef:
                    type: string
                  generatedAt:
                    type: string
                    format: date-time
                  cases:
                    type: array
                    items:
                      type: object
                      required:
                        - caseId
                        - externalCaseRef
                        - customerRef
                        - caseTypeCode
                        - reasonCode
                        - status
                        - priority
                        - ownerQueueCode
                        - serviceLevelDueAt
                        - lastUpdatedAt
                        - sensitive
                      properties:
                        caseId:
                          type: integer
                          description: Stable opaque servicing case identifier.
                        externalCaseRef:
                          type: string
                        customerRef:
                          type: string
                        caseTypeCode:
                          type: string
                        reasonCode:
                          type: string
                          description: Configured structured reason code.
                        status:
                          type: string
                          description: Current normalized lifecycle state.
                        priority:
                          type: string
                        ownerQueueCode:
                          type: string
                        serviceLevelDueAt:
                          type: string
                          format: date-time
                        lastUpdatedAt:
                          type: string
                          format: date-time
                        sensitive:
                          type: boolean
                  decisions:
                    type: array
                    items:
                      type: object
                  interactions:
                    type: array
                    items:
                      type: object
                      required:
                        - interactionId
                        - customerRef
                        - caseId
                        - channel
                        - direction
                        - interactionType
                        - reasonCode
                        - status
                        - verificationState
                        - contentSummary
                        - createdAt
                      properties:
                        interactionId:
                          type: integer
                        customerRef:
                          type: string
                        caseId:
                          type: integer
                          description: Stable opaque servicing case identifier.
                        channel:
                          type: string
                        direction:
                          type: string
                        interactionType:
                          type: string
                        reasonCode:
                          type: string
                          description: Configured structured reason code.
                        status:
                          type: string
                          description: Current normalized lifecycle state.
                        verificationState:
                          type: string
                        contentSummary:
                          type: string
                        createdAt:
                          type: string
                          format: date-time
                  actionRequests:
                    type: array
                    items:
                      type: object
                  effects:
                    type: array
                    items:
                      type: object
                      required:
                        - effectRef
                        - caseId
                        - effectType
                        - triggerType
                        - status
                        - attemptCount
                        - createdAt
                        - completedAt
                      properties:
                        effectRef:
                          type: string
                        caseId:
                          type: integer
                          description: Stable opaque servicing case identifier.
                        effectType:
                          type: string
                        triggerType:
                          type: string
                        status:
                          type: string
                          description: Current normalized lifecycle state.
                        attemptCount:
                          type: integer
                        createdAt:
                          type: string
                          format: date-time
                        completedAt:
                          type: string
                          format: date-time
                  integrity:
                    type: object
                    required:
                      - chainComplete
                    properties:
                      chainComplete:
                        type: boolean
              example:
                subjectType: CUSTOMER
                subjectRef: "123"
                generatedAt: 2026-07-25T18:30:00Z
                cases:
                  - caseId: 1001
                    externalCaseRef: LE-CASE-1001
                    customerRef: "123"
                    caseTypeCode: COLLECTIONS
                    reasonCode: DELINQUENCY_SIGNAL
                    status: OPEN
                    priority: HIGH
                    ownerQueueCode: COLLECTIONS
                    serviceLevelDueAt: 2026-07-26T17:00:00Z
                    lastUpdatedAt: 2026-07-25T18:30:00Z
                    sensitive: false
                decisions: []
                interactions:
                  - interactionId: 3001
                    customerRef: "123"
                    caseId: 1001
                    channel: EMAIL
                    direction: INBOUND
                    interactionType: MESSAGE
                    reasonCode: PAYMENT_QUESTION
                    status: COMPLETED
                    verificationState: NOT_APPLICABLE
                    contentSummary: Customer asks why a payment did not post.
                    createdAt: 2026-07-25T18:30:00Z
                actionRequests: []
                effects:
                  - effectRef: effect-cancel-autopay-1001-1
                    caseId: 1001
                    effectType: CANCEL_AUTOPAY
                    triggerType: LMS_EVENT
                    status: COMPLETED
                    attemptCount: 1
                    createdAt: 2026-07-25T18:30:00Z
                    completedAt: 2026-07-25T18:30:02Z
                integrity:
                  chainComplete: true
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
  /v1/servicing/admin/case-types:
    get:
      tags:
        - Servicing administration
      operationId: listCaseTypeAdmin
      summary: List the case-type admin catalog
      description: Returns the complete case-type admin catalog, disabled types included, with reasons, per-reason workflow
        resolution, workflow keys, and protective scopes.
      x-permission: ADMIN_SERVICING_CONFIG
      x-idempotent: false
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - items
                properties:
                  items:
                    type: array
                    items:
                      type: object
                      required:
                        - caseTypeCode
                        - displayName
                        - enabled
                        - defaultPriority
                        - serviceLevelMinutes
                        - openCases
                        - activeWorkflow
                        - defaultWorkflow
                        - reasons
                        - workflowKeys
                        - protectiveScopes
                      properties:
                        caseTypeCode:
                          type: string
                        displayName:
                          type: string
                        enabled:
                          type: boolean
                        defaultPriority:
                          type: string
                        serviceLevelMinutes:
                          type: integer
                        openCases:
                          type: integer
                        activeWorkflow:
                          type: object
                          required:
                            - workflowKey
                            - versionNumber
                          properties:
                            workflowKey:
                              type: string
                            versionNumber:
                              type: integer
                        defaultWorkflow:
                          type: object
                          required:
                            - workflowKey
                            - versionNumber
                            - active
                          properties:
                            workflowKey:
                              type: string
                            versionNumber:
                              type: integer
                            active:
                              type: boolean
                        reasons:
                          type: array
                          items:
                            type: object
                            required:
                              - reasonCode
                              - displayName
                              - enabled
                              - handlingMode
                              - resolution
                            properties:
                              reasonCode:
                                type: string
                                description: Configured structured reason code.
                              displayName:
                                type: string
                              enabled:
                                type: boolean
                              handlingMode:
                                type: string
                              resolution:
                                type: object
                                required:
                                  - resolved
                                  - workflowKey
                                  - versionNumber
                                  - note
                                properties:
                                  resolved:
                                    type: boolean
                                  workflowKey:
                                    type: string
                                  versionNumber:
                                    type: integer
                                  note:
                                    type: string
                        workflowKeys:
                          type: array
                          items:
                            type: string
                        protectiveScopes:
                          type: array
                          items:
                            type: object
                            required:
                              - proposedAction
                              - channel
                            properties:
                              proposedAction:
                                type: string
                              channel:
                                type: string
              example:
                items:
                  - caseTypeCode: COLLECTIONS
                    displayName: Collections
                    enabled: true
                    defaultPriority: NORMAL
                    serviceLevelMinutes: 1440
                    openCases: 12
                    activeWorkflow:
                      workflowKey: COLLECTIONS_DEFAULT
                      versionNumber: 2
                    defaultWorkflow:
                      workflowKey: COLLECTIONS_DEFAULT
                      versionNumber: 2
                      active: true
                    reasons:
                      - reasonCode: DELINQUENCY_SIGNAL
                        displayName: Delinquency signal
                        enabled: true
                        handlingMode: WORKFLOW
                        resolution:
                          resolved: true
                          workflowKey: COLLECTIONS_DEFAULT
                          versionNumber: 2
                          note: type default
                    workflowKeys:
                      - COLLECTIONS_DEFAULT
                    protectiveScopes:
                      - proposedAction: INITIATE_CONTACT
                        channel: PHONE
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
    post:
      tags:
        - Servicing administration
      operationId: createCaseType
      summary: Create a case type
      description: Creates a case type born disabled, with no reasons and empty field definitions; it stays invisible to
        workers until it is deliberately enabled.
      x-permission: ADMIN_SERVICING_CONFIG
      x-idempotent: true
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: Idempotency-Key
          in: header
          required: false
          description: Optional replay key for this logical mutation. Omission creates a fresh server-owned key for this attempt;
            blank, repeated, or longer-than-50-character values are rejected.
          schema:
            type: string
            minLength: 1
            maxLength: 50
      responses:
        "201":
          description: Created.
          content:
            application/json:
              schema:
                type: object
                required:
                  - resourceId
                  - changes
                properties:
                  resourceId:
                    type: integer
                  changes:
                    type: object
                    required:
                      - operation
                    properties:
                      operation:
                        type: string
              example:
                resourceId: 12
                changes:
                  operation: CREATE_CASE_TYPE
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
        "409":
          $ref: "#/components/responses/Servicing409Error"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - code
                - displayName
                - reason
              properties:
                code:
                  type: string
                displayName:
                  type: string
                defaultPriority:
                  type: string
                serviceLevelMinutes:
                  type: integer
                reason:
                  type: string
              example:
                code: HARDSHIP_REVIEW
                displayName: Hardship review
                defaultPriority: NORMAL
                serviceLevelMinutes: 2880
                reason: Introduce a dedicated hardship review case type.
            example:
              code: HARDSHIP_REVIEW
              displayName: Hardship review
              defaultPriority: NORMAL
              serviceLevelMinutes: 2880
              reason: Introduce a dedicated hardship review case type.
  /v1/servicing/admin/case-types/{caseTypeCode}:
    get:
      tags:
        - Servicing administration
      operationId: getCaseTypeAdmin
      summary: Retrieve one case type for administration
      description: "Returns the full admin view of one case type: the list projection plus its current field definitions and
        configured review timers."
      x-permission: ADMIN_SERVICING_CONFIG
      x-idempotent: false
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: caseTypeCode
          in: path
          required: true
          description: Stable opaque caseTypeCode identifier.
          schema:
            type: string
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - caseTypeCode
                  - displayName
                  - enabled
                  - defaultPriority
                  - serviceLevelMinutes
                  - openCases
                  - activeWorkflow
                  - defaultWorkflow
                  - reasons
                  - workflowKeys
                  - protectiveScopes
                  - fieldDefinitions
                  - reviewTimers
                properties:
                  caseTypeCode:
                    type: string
                  displayName:
                    type: string
                  enabled:
                    type: boolean
                  defaultPriority:
                    type: string
                  serviceLevelMinutes:
                    type: integer
                  openCases:
                    type: integer
                  activeWorkflow:
                    type: object
                    required:
                      - workflowKey
                      - versionNumber
                    properties:
                      workflowKey:
                        type: string
                      versionNumber:
                        type: integer
                  defaultWorkflow:
                    type: object
                    required:
                      - workflowKey
                      - versionNumber
                      - active
                    properties:
                      workflowKey:
                        type: string
                      versionNumber:
                        type: integer
                      active:
                        type: boolean
                  reasons:
                    type: array
                    items:
                      type: object
                      required:
                        - reasonCode
                        - displayName
                        - enabled
                        - handlingMode
                        - resolution
                      properties:
                        reasonCode:
                          type: string
                          description: Configured structured reason code.
                        displayName:
                          type: string
                        enabled:
                          type: boolean
                        handlingMode:
                          type: string
                        resolution:
                          type: object
                          required:
                            - resolved
                            - workflowKey
                            - versionNumber
                            - note
                          properties:
                            resolved:
                              type: boolean
                            workflowKey:
                              type: string
                            versionNumber:
                              type: integer
                            note:
                              type: string
                  workflowKeys:
                    type: array
                    items:
                      type: string
                  protectiveScopes:
                    type: array
                    items:
                      type: object
                      required:
                        - proposedAction
                        - channel
                      properties:
                        proposedAction:
                          type: string
                        channel:
                          type: string
                  fieldDefinitions:
                    type: object
                    required:
                      - sections
                    properties:
                      sections:
                        type: array
                        items:
                          type: object
                          required:
                            - key
                            - label
                            - fields
                          properties:
                            key:
                              type: string
                            label:
                              type: string
                            fields:
                              type: array
                              items:
                                type: object
                                required:
                                  - key
                                  - label
                                  - type
                                  - requiredAt
                                properties:
                                  key:
                                    type: string
                                  label:
                                    type: string
                                  type:
                                    type: string
                                  requiredAt:
                                    type: string
                                    format: date-time
                  reviewTimers:
                    type: array
                    items:
                      type: object
                      required:
                        - stageKey
                        - taskTypeCode
                        - queueCode
                        - firstDueDays
                        - repeatEveryDays
                        - active
                      properties:
                        stageKey:
                          type: string
                        taskTypeCode:
                          type: string
                        queueCode:
                          type: string
                        firstDueDays:
                          type: integer
                        repeatEveryDays:
                          type: integer
                        active:
                          type: boolean
              example:
                caseTypeCode: COLLECTIONS
                displayName: Collections
                enabled: true
                defaultPriority: NORMAL
                serviceLevelMinutes: 1440
                openCases: 12
                activeWorkflow:
                  workflowKey: COLLECTIONS_DEFAULT
                  versionNumber: 2
                defaultWorkflow:
                  workflowKey: COLLECTIONS_DEFAULT
                  versionNumber: 2
                  active: true
                reasons:
                  - reasonCode: DELINQUENCY_SIGNAL
                    displayName: Delinquency signal
                    enabled: true
                    handlingMode: WORKFLOW
                    resolution:
                      resolved: true
                      workflowKey: COLLECTIONS_DEFAULT
                      versionNumber: 2
                      note: type default
                workflowKeys:
                  - COLLECTIONS_DEFAULT
                protectiveScopes:
                  - proposedAction: INITIATE_CONTACT
                    channel: PHONE
                fieldDefinitions:
                  sections:
                    - key: service_details
                      label: Service details
                      fields:
                        - key: delinquency_bucket
                          label: Delinquency bucket
                          type: TEXT
                          requiredAt: OPTIONAL
                reviewTimers:
                  - stageKey: MONITORING
                    taskTypeCode: COLLECTIONS_OUTREACH
                    queueCode: COLLECTIONS
                    firstDueDays: 7
                    repeatEveryDays: 7
                    active: true
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
    put:
      tags:
        - Servicing administration
      operationId: updateCaseType
      summary: Update a case type
      description: Updates display name, default priority, service level, or enablement. Enabling requires at least one
        enabled reason and an ACTIVE-resolvable workflow for every enabled reason.
      x-permission: ADMIN_SERVICING_CONFIG
      x-idempotent: true
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: caseTypeCode
          in: path
          required: true
          description: Stable opaque caseTypeCode identifier.
          schema:
            type: string
        - name: Idempotency-Key
          in: header
          required: false
          description: Optional replay key for this logical mutation. Omission creates a fresh server-owned key for this attempt;
            blank, repeated, or longer-than-50-character values are rejected.
          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:
                      - operation
                      - caseTypeCode
                      - defaultPriority
                      - enabled
                    properties:
                      operation:
                        type: string
                      caseTypeCode:
                        type: string
                      defaultPriority:
                        type: string
                      enabled:
                        type: boolean
              example:
                resourceId: 0
                changes:
                  operation: UPDATE_CASE_TYPE
                  caseTypeCode: COLLECTIONS
                  defaultPriority: HIGH
                  enabled: true
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
        "409":
          $ref: "#/components/responses/Servicing409Error"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - reason
              properties:
                displayName:
                  type: string
                defaultPriority:
                  type: string
                serviceLevelMinutes:
                  type: integer
                enabled:
                  type: boolean
                reason:
                  type: string
              example:
                displayName: Collections
                defaultPriority: HIGH
                serviceLevelMinutes: 1440
                enabled: true
                reason: Raise the default priority for delinquency work.
            example:
              displayName: Collections
              defaultPriority: HIGH
              serviceLevelMinutes: 1440
              enabled: true
              reason: Raise the default priority for delinquency work.
  /v1/servicing/admin/case-types/{caseTypeCode}/reasons:
    post:
      tags:
        - Servicing administration
      operationId: createCaseReason
      summary: Create a case reason
      description: Adds a reason to an existing case type. Handling mode defaults to WORKFLOW; a workflow-key override must
        belong to the same case type and, on an enabled type and reason, have an ACTIVE version.
      x-permission: ADMIN_SERVICING_CONFIG
      x-idempotent: true
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: caseTypeCode
          in: path
          required: true
          description: Stable opaque caseTypeCode identifier.
          schema:
            type: string
        - name: Idempotency-Key
          in: header
          required: false
          description: Optional replay key for this logical mutation. Omission creates a fresh server-owned key for this attempt;
            blank, repeated, or longer-than-50-character values are rejected.
          schema:
            type: string
            minLength: 1
            maxLength: 50
      responses:
        "201":
          description: Created.
          content:
            application/json:
              schema:
                type: object
                required:
                  - resourceId
                  - changes
                properties:
                  resourceId:
                    type: integer
                  changes:
                    type: object
                    required:
                      - operation
                      - caseTypeCode
                    properties:
                      operation:
                        type: string
                      caseTypeCode:
                        type: string
              example:
                resourceId: 31
                changes:
                  operation: CREATE_REASON
                  caseTypeCode: COLLECTIONS
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
        "409":
          $ref: "#/components/responses/Servicing409Error"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - code
                - displayName
                - reason
              properties:
                code:
                  type: string
                displayName:
                  type: string
                handlingMode:
                  type: string
                workflowKey:
                  type: string
                enabled:
                  type: boolean
                reason:
                  type: string
              example:
                code: PAYMENT_DISPUTE
                displayName: Payment dispute
                handlingMode: WORKFLOW
                workflowKey: COLLECTIONS_DEFAULT
                enabled: true
                reason: Route payment disputes through the collections flow.
            example:
              code: PAYMENT_DISPUTE
              displayName: Payment dispute
              handlingMode: WORKFLOW
              workflowKey: COLLECTIONS_DEFAULT
              enabled: true
              reason: Route payment disputes through the collections flow.
  /v1/servicing/admin/case-types/{caseTypeCode}/reasons/{reasonCode}:
    put:
      tags:
        - Servicing administration
      operationId: updateCaseReason
      summary: Update a case reason
      description: Updates display name, handling mode, workflow-key override, or enablement of an existing reason.
        Re-enabling a reason re-checks the workflow resolution it will live under.
      x-permission: ADMIN_SERVICING_CONFIG
      x-idempotent: true
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: caseTypeCode
          in: path
          required: true
          description: Stable opaque caseTypeCode identifier.
          schema:
            type: string
        - name: reasonCode
          in: path
          required: true
          description: Configured structured reason code.
          schema:
            type: string
        - name: Idempotency-Key
          in: header
          required: false
          description: Optional replay key for this logical mutation. Omission creates a fresh server-owned key for this attempt;
            blank, repeated, or longer-than-50-character values are rejected.
          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:
                      - operation
                      - caseTypeCode
                      - reasonCode
                      - workflowKey
                      - enabled
                    properties:
                      operation:
                        type: string
                      caseTypeCode:
                        type: string
                      reasonCode:
                        type: string
                        description: Configured structured reason code.
                      workflowKey:
                        type: string
                      enabled:
                        type: boolean
              example:
                resourceId: 0
                changes:
                  operation: UPDATE_REASON
                  caseTypeCode: COLLECTIONS
                  reasonCode: PAYMENT_DISPUTE
                  workflowKey: COLLECTIONS_DEFAULT
                  enabled: true
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
        "409":
          $ref: "#/components/responses/Servicing409Error"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - reason
              properties:
                displayName:
                  type: string
                handlingMode:
                  type: string
                workflowKey:
                  type: string
                enabled:
                  type: boolean
                reason:
                  type: string
              example:
                displayName: Payment dispute
                handlingMode: WORKFLOW
                workflowKey: COLLECTIONS_DEFAULT
                enabled: true
                reason: Point the reason at the collections workflow.
            example:
              displayName: Payment dispute
              handlingMode: WORKFLOW
              workflowKey: COLLECTIONS_DEFAULT
              enabled: true
              reason: Point the reason at the collections workflow.
  /v1/servicing/admin/case-types/{caseTypeCode}/review-timers:
    put:
      tags:
        - Servicing administration
      operationId: replaceCaseReviewTimers
      summary: Replace review timers
      description: Fully replaces the review-timer rows of a case type. A timer naming a stage outside the ACTIVE workflow is
        accepted with a warning, since timers may pre-stage a version not yet ACTIVE.
      x-permission: ADMIN_SERVICING_CONFIG
      x-idempotent: true
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: caseTypeCode
          in: path
          required: true
          description: Stable opaque caseTypeCode identifier.
          schema:
            type: string
        - name: Idempotency-Key
          in: header
          required: false
          description: Optional replay key for this logical mutation. Omission creates a fresh server-owned key for this attempt;
            blank, repeated, or longer-than-50-character values are rejected.
          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:
                      - operation
                      - caseTypeCode
                      - timers
                    properties:
                      operation:
                        type: string
                      caseTypeCode:
                        type: string
                      timers:
                        type: integer
              example:
                resourceId: 1
                changes:
                  operation: REPLACE_REVIEW_TIMERS
                  caseTypeCode: COLLECTIONS
                  timers: 1
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
        "409":
          $ref: "#/components/responses/Servicing409Error"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - timers
                - reason
              properties:
                timers:
                  type: array
                  items:
                    type: object
                    required:
                      - stageKey
                      - taskTypeCode
                      - queueCode
                      - firstDueDays
                      - repeatEveryDays
                      - active
                    properties:
                      stageKey:
                        type: string
                      taskTypeCode:
                        type: string
                      queueCode:
                        type: string
                      firstDueDays:
                        type: integer
                      repeatEveryDays:
                        type: integer
                      active:
                        type: boolean
                reason:
                  type: string
              example:
                timers:
                  - stageKey: MONITORING
                    taskTypeCode: COLLECTIONS_OUTREACH
                    queueCode: COLLECTIONS
                    firstDueDays: 7
                    repeatEveryDays: 7
                    active: true
                reason: Review monitored collections cases weekly.
            example:
              timers:
                - stageKey: MONITORING
                  taskTypeCode: COLLECTIONS_OUTREACH
                  queueCode: COLLECTIONS
                  firstDueDays: 7
                  repeatEveryDays: 7
                  active: true
              reason: Review monitored collections cases weekly.
  /v1/servicing/admin/allocation:
    get:
      tags:
        - Servicing administration
      operationId: getAllocationSettings
      summary: Read the allocation policy
      description: "Returns the servicing-wide allocation settings: whether work is pushed automatically, reservation and
        concurrency limits, and the callback timing windows."
      x-permission: ADMIN_SERVICING_ALLOCATION
      x-idempotent: false
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - automaticAllocationEnabled
                  - reservationSeconds
                  - maxActiveTasks
                  - maxActiveVoiceTasks
                  - maxUnansweredReservations
                  - callbackAtRiskMinutes
                  - callbackWindowMinutes
                  - callbackMaxHorizonDays
                properties:
                  automaticAllocationEnabled:
                    type: boolean
                  reservationSeconds:
                    type: integer
                  maxActiveTasks:
                    type: integer
                  maxActiveVoiceTasks:
                    type: integer
                  maxUnansweredReservations:
                    type: integer
                  callbackAtRiskMinutes:
                    type: integer
                  callbackWindowMinutes:
                    type: integer
                  callbackMaxHorizonDays:
                    type: integer
              example:
                automaticAllocationEnabled: true
                reservationSeconds: 120
                maxActiveTasks: 8
                maxActiveVoiceTasks: 2
                maxUnansweredReservations: 3
                callbackAtRiskMinutes: 30
                callbackWindowMinutes: 60
                callbackMaxHorizonDays: 14
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
    put:
      tags:
        - Servicing administration
      operationId: updateAllocationSettings
      summary: Update the allocation policy
      description: Partially updates the servicing-wide allocation settings and returns the full saved policy. A worker cannot
        hold more voice work than work in total, and a callback cannot be flagged at risk after its window.
      x-permission: UPDATE_SERVICING_ALLOCATION
      x-idempotent: true
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: Idempotency-Key
          in: header
          required: false
          description: Optional replay key for this logical mutation. Omission creates a fresh server-owned key for this attempt;
            blank, repeated, or longer-than-50-character values are rejected.
          schema:
            type: string
            minLength: 1
            maxLength: 50
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - automaticAllocationEnabled
                  - reservationSeconds
                  - maxActiveTasks
                  - maxActiveVoiceTasks
                  - maxUnansweredReservations
                  - callbackAtRiskMinutes
                  - callbackWindowMinutes
                  - callbackMaxHorizonDays
                properties:
                  automaticAllocationEnabled:
                    type: boolean
                  reservationSeconds:
                    type: integer
                  maxActiveTasks:
                    type: integer
                  maxActiveVoiceTasks:
                    type: integer
                  maxUnansweredReservations:
                    type: integer
                  callbackAtRiskMinutes:
                    type: integer
                  callbackWindowMinutes:
                    type: integer
                  callbackMaxHorizonDays:
                    type: integer
              example:
                automaticAllocationEnabled: true
                reservationSeconds: 120
                maxActiveTasks: 8
                maxActiveVoiceTasks: 2
                maxUnansweredReservations: 3
                callbackAtRiskMinutes: 30
                callbackWindowMinutes: 60
                callbackMaxHorizonDays: 14
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
        "409":
          $ref: "#/components/responses/Servicing409Error"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - automaticAllocationEnabled
                - maxActiveTasks
                - maxActiveVoiceTasks
              properties:
                automaticAllocationEnabled:
                  type: boolean
                maxActiveTasks:
                  type: integer
                maxActiveVoiceTasks:
                  type: integer
              example:
                automaticAllocationEnabled: true
                maxActiveTasks: 8
                maxActiveVoiceTasks: 2
            example:
              automaticAllocationEnabled: true
              maxActiveTasks: 8
              maxActiveVoiceTasks: 2
  /v1/servicing/admin/queues:
    get:
      tags:
        - Servicing administration
      operationId: listQueueCoverage
      summary: List queues with coverage
      description: Returns every enabled queue with its members, availability, open and unoffered work, and a staffing warning
        where one is due, so an unstaffed queue is visible before its work silently accumulates.
      x-permission: ADMIN_SERVICING_ALLOCATION
      x-idempotent: false
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: array
                items:
                  type: object
                  required:
                    - queueCode
                    - displayName
                    - memberCount
                    - availableMembers
                    - membersWithCapacity
                    - openTasks
                    - unofferedTasks
                    - warning
                    - members
                  properties:
                    queueCode:
                      type: string
                    displayName:
                      type: string
                    memberCount:
                      type: integer
                    availableMembers:
                      type: integer
                    membersWithCapacity:
                      type: integer
                    openTasks:
                      type: integer
                    unofferedTasks:
                      type: integer
                    warning:
                      type: string
                    members:
                      type: array
                      items:
                        type: object
                        required:
                          - workerId
                          - displayName
                          - presenceState
                          - activeTasks
                          - capacity
                        properties:
                          workerId:
                            type: integer
                          displayName:
                            type: string
                          presenceState:
                            type: string
                          activeTasks:
                            type: integer
                          capacity:
                            type: integer
              example:
                - queueCode: COLLECTIONS
                  displayName: Collections
                  memberCount: 1
                  availableMembers: 1
                  membersWithCapacity: 0
                  openTasks: 5
                  unofferedTasks: 2
                  warning: Work is waiting and every available member is at capacity
                  members:
                    - workerId: 4101
                      displayName: Maria Agent
                      presenceState: AVAILABLE
                      activeTasks: 8
                      capacity: 8
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
  /v1/servicing/admin/queues/{queueCode}/members:
    post:
      tags:
        - Servicing administration
      operationId: updateQueueMembers
      summary: Update queue membership
      description: Adds and removes queue members by worker ID in one call. Memberships stay explicit auditable rows, never
        routing rules hidden inside a role.
      x-permission: ADMIN_SERVICING_ALLOCATION
      x-idempotent: true
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: queueCode
          in: path
          required: true
          description: Stable opaque queueCode identifier.
          schema:
            type: string
        - name: Idempotency-Key
          in: header
          required: false
          description: Optional replay key for this logical mutation. Omission creates a fresh server-owned key for this attempt;
            blank, repeated, or longer-than-50-character values are rejected.
          schema:
            type: string
            minLength: 1
            maxLength: 50
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - queueCode
                  - added
                  - removed
                properties:
                  queueCode:
                    type: string
                  added:
                    type: integer
                  removed:
                    type: integer
              example:
                queueCode: COLLECTIONS
                added: 1
                removed: 1
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
        "409":
          $ref: "#/components/responses/Servicing409Error"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - add
                - remove
              properties:
                add:
                  type: array
                  items:
                    type: integer
                remove:
                  type: array
                  items:
                    type: integer
              example:
                add:
                  - 4101
                remove:
                  - 4102
            example:
              add:
                - 4101
              remove:
                - 4102
  /v1/servicing/case-types/{caseTypeCode}/workflow:
    get:
      tags:
        - Servicing administration
      operationId: getCaseTypeWorkflow
      summary: Read the active workflow shape
      description: "Projects the ACTIVE workflow of an enabled case type: each stage, the facts it needs, the work it plans,
        and where it can go. A branch is described by the facts it turns on; predicate rules stay server-side."
      x-permission: READ_SERVICING_CASE
      x-idempotent: false
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: caseTypeCode
          in: path
          required: true
          description: Stable opaque caseTypeCode identifier.
          schema:
            type: string
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - caseTypeCode
                  - workflowKey
                  - version
                  - stages
                properties:
                  caseTypeCode:
                    type: string
                  workflowKey:
                    type: string
                  version:
                    type: integer
                    description: Monotonically increasing resource version.
                  stages:
                    type: array
                    items:
                      type: object
                      required:
                        - stageKey
                        - displayName
                        - terminal
                        - requiredFacts
                        - taskTemplates
                        - next
                      properties:
                        stageKey:
                          type: string
                        displayName:
                          type: string
                        terminal:
                          type: boolean
                        requiredFacts:
                          type: array
                          items:
                            type: string
                        taskTemplates:
                          type: array
                          items:
                            type: object
                            required:
                              - taskTypeCode
                              - displayName
                              - queueCode
                              - conditional
                            properties:
                              taskTypeCode:
                                type: string
                              displayName:
                                type: string
                              queueCode:
                                type: string
                              conditional:
                                type: boolean
                        next:
                          type: array
                          items:
                            type: object
                            required:
                              - stage
                              - isDefault
                              - dependsOn
                            properties:
                              stage:
                                type: string
                              isDefault:
                                type: boolean
                              dependsOn:
                                type: array
                                items:
                                  type: string
              example:
                caseTypeCode: COLLECTIONS
                workflowKey: COLLECTIONS_DEFAULT
                version: 2
                stages:
                  - stageKey: MONITORING
                    displayName: Monitor the promise
                    terminal: false
                    requiredFacts:
                      - promiseToPayState
                    taskTemplates:
                      - taskTypeCode: COLLECTIONS_OUTREACH
                        displayName: Collections outreach
                        queueCode: COLLECTIONS
                        conditional: false
                    next:
                      - stage: CLOSE
                        isDefault: false
                        dependsOn:
                          - promiseToPayState
                      - stage: MONITORING
                        isDefault: true
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
  /v1/servicing/admin/workflow-definitions:
    get:
      tags:
        - Workflow administration
      operationId: listWorkflowDefinitions
      summary: List workflow definitions
      description: "Lists every workflow key with its case type and versions: status, row version, stage count, activation and
        retirement timestamps, and how many open cases stay pinned to each version."
      x-permission: READ_SERVICING_WORKFLOW_DEFINITION
      x-idempotent: false
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - items
                properties:
                  items:
                    type: array
                    items:
                      type: object
                      required:
                        - workflowKey
                        - caseTypeCode
                        - caseTypeDisplayName
                        - activeVersion
                        - versions
                      properties:
                        workflowKey:
                          type: string
                        caseTypeCode:
                          type: string
                        caseTypeDisplayName:
                          type: string
                        activeVersion:
                          type: integer
                        versions:
                          type: array
                          items:
                            type: object
                            required:
                              - versionNumber
                              - status
                              - discarded
                              - rowVersion
                              - activatedAt
                              - stageCount
                              - openPinnedCases
                            properties:
                              versionNumber:
                                type: integer
                              status:
                                type: string
                                description: Current normalized lifecycle state.
                              discarded:
                                type: boolean
                              rowVersion:
                                type: integer
                              activatedAt:
                                type: string
                                format: date-time
                              stageCount:
                                type: integer
                              openPinnedCases:
                                type: integer
              example:
                items:
                  - workflowKey: COLLECTIONS_DEFAULT
                    caseTypeCode: COLLECTIONS
                    caseTypeDisplayName: Collections
                    activeVersion: 2
                    versions:
                      - versionNumber: 2
                        status: ACTIVE
                        discarded: false
                        rowVersion: 5
                        activatedAt: 2026-07-20T12:00:00Z
                        stageCount: 4
                        openPinnedCases: 12
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
    post:
      tags:
        - Workflow administration
      operationId: createWorkflowDefinition
      summary: Draft a new workflow key
      description: Drafts version 1 of a new workflow key from a supplied definition, a copy of an existing version, or the
        minimal scaffold. Server truth restamps key, version, and case type over whatever the body claims.
      x-permission: ADMIN_SERVICING_WORKFLOW_DEFINITION
      x-idempotent: true
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: Idempotency-Key
          in: header
          required: false
          description: Optional replay key for this logical mutation. Omission creates a fresh server-owned key for this attempt;
            blank, repeated, or longer-than-50-character values are rejected.
          schema:
            type: string
            minLength: 1
            maxLength: 50
      responses:
        "201":
          description: Created.
          content:
            application/json:
              schema:
                type: object
                required:
                  - resourceId
                  - changes
                properties:
                  resourceId:
                    type: integer
                  changes:
                    type: object
                    required:
                      - operation
                      - versionNumber
                    properties:
                      operation:
                        type: string
                      versionNumber:
                        type: integer
              example:
                resourceId: 41
                changes:
                  operation: CREATE_KEY
                  versionNumber: 1
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
        "409":
          $ref: "#/components/responses/Servicing409Error"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - caseTypeCode
                - workflowKey
                - reason
              properties:
                caseTypeCode:
                  type: string
                workflowKey:
                  type: string
                copyFromWorkflowKey:
                  type: string
                copyFromVersion:
                  type: integer
                reason:
                  type: string
              example:
                caseTypeCode: COLLECTIONS
                workflowKey: COLLECTIONS_HARDSHIP
                copyFromWorkflowKey: COLLECTIONS_DEFAULT
                copyFromVersion: 2
                reason: Start a hardship variant of the collections flow.
            example:
              caseTypeCode: COLLECTIONS
              workflowKey: COLLECTIONS_HARDSHIP
              copyFromWorkflowKey: COLLECTIONS_DEFAULT
              copyFromVersion: 2
              reason: Start a hardship variant of the collections flow.
  /v1/servicing/admin/workflow-definitions/vocabulary:
    get:
      tags:
        - Workflow administration
      operationId: getWorkflowDefinitionVocabulary
      summary: Read the authoring vocabulary
      description: "Returns everything a definition may reference: predicate sources, operators, and named conditions, plus
        live task types with their outcome catalogs, queues, effects, wait statuses, priorities, approval roles, and
        case types."
      x-permission: READ_SERVICING_WORKFLOW_DEFINITION
      x-idempotent: false
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - predicate
                  - taskTypes
                  - queues
                  - effects
                  - waitStatuses
                  - priorities
                  - approvalRoles
                  - gatesAdvisory
                  - caseTypes
                properties:
                  predicate:
                    type: object
                    required:
                      - sources
                      - operators
                      - namedConditions
                    properties:
                      sources:
                        type: array
                        items:
                          type: object
                          required:
                            - source
                            - fields
                          properties:
                            source:
                              type: string
                              description: System or actor that originated the record.
                            fields:
                              type: array
                              items:
                                type: string
                      operators:
                        type: array
                        items:
                          type: string
                      namedConditions:
                        type: array
                        items:
                          type: string
                  taskTypes:
                    type: array
                    items:
                      type: object
                      required:
                        - code
                        - displayName
                        - defaultQueueCode
                        - outcomeCatalogEnforced
                        - outcomes
                      properties:
                        code:
                          type: string
                        displayName:
                          type: string
                        defaultQueueCode:
                          type: string
                        outcomeCatalogEnforced:
                          type: boolean
                        outcomes:
                          type: array
                          items:
                            type: object
                            required:
                              - code
                              - displayName
                            properties:
                              code:
                                type: string
                              displayName:
                                type: string
                  queues:
                    type: array
                    items:
                      type: object
                      required:
                        - code
                        - displayName
                      properties:
                        code:
                          type: string
                        displayName:
                          type: string
                  effects:
                    type: object
                    required:
                      - types
                      - targets
                      - failurePolicies
                    properties:
                      types:
                        type: array
                        items:
                          type: object
                          required:
                            - code
                            - restricted
                            - note
                          properties:
                            code:
                              type: string
                            restricted:
                              type: boolean
                            note:
                              type: string
                      targets:
                        type: array
                        items:
                          type: string
                      failurePolicies:
                        type: array
                        items:
                          type: string
                  waitStatuses:
                    type: array
                    items:
                      type: string
                  priorities:
                    type: array
                    items:
                      type: string
                  approvalRoles:
                    type: array
                    items:
                      type: string
                  gatesAdvisory:
                    type: string
                  caseTypes:
                    type: array
                    items:
                      type: object
                      required:
                        - code
                        - displayName
                      properties:
                        code:
                          type: string
                        displayName:
                          type: string
              example:
                predicate:
                  sources:
                    - source: fact
                      fields:
                        - daysOverdue
                        - loanStatus
                        - overdueAmount
                        - promiseToPayState
                    - source: task
                      fields: []
                      note: field is <TASK_TYPE>.status or <TASK_TYPE>.outcome; types and their closed outcome catalogs are in taskTypes
                    - source: caseEffect
                      fields: []
                      freeKey: true
                  operators:
                    - CONTAINS
                    - EQ
                    - EXISTS
                    - GT
                    - GTE
                    - IN
                    - LT
                    - LTE
                    - NE
                    - NOT_CONTAINS
                    - NOT_EXISTS
                    - NOT_IN
                  namedConditions:
                    - CASE_CLOSURE_GUARDRAILS_SATISFIED
                    - PTP_GUARDRAIL_POLICY_SATISFIED
                taskTypes:
                  - code: COLLECTIONS_OUTREACH
                    displayName: Collections outreach
                    defaultQueueCode: COLLECTIONS
                    outcomeCatalogEnforced: true
                    outcomes:
                      - code: CUSTOMER_REACHED
                        displayName: Customer reached
                      - code: NO_ANSWER
                        displayName: No answer
                queues:
                  - code: COLLECTIONS
                    displayName: Collections
                effects:
                  types:
                    - code: CANCEL_AUTOPAY
                      restricted: true
                      note: The executor builds a PAYMENT_RETURN context; declare this only on the payment-return path (DEC-2026-08-25-01d)
                    - code: RELEASE_PROTECTIVE_STATE
                  targets:
                    - CASE_CUSTOMER
                    - SIGNAL_LOAN
                  failurePolicies:
                    - RETRY_THEN_REVIEW
                waitStatuses:
                  - WAITING_ON_BORROWER
                  - WAITING_ON_LMS
                priorities:
                  - LOW
                  - NORMAL
                  - HIGH
                  - CRITICAL
                approvalRoles:
                  - SPECIALIST
                  - SUPERVISOR
                gatesAdvisory: Evidence and approval gates stay out of ACTIVE definitions until the runtime supplies those snapshot
                  sources (DEC-2026-08-14-01); activation warns when a definition declares them.
                caseTypes:
                  - code: COLLECTIONS
                    displayName: Collections
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
  /v1/servicing/admin/workflow-definitions/export:
    get:
      tags:
        - Workflow administration
      operationId: exportWorkflowDefinitions
      summary: Export workflow definitions
      description: Exports definitions as a versioned bundle suitable for re-import, optionally limited to one key and
        excluding RETIRED versions by default.
      x-permission: READ_SERVICING_WORKFLOW_DEFINITION
      x-idempotent: false
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: workflowKey
          in: query
          required: false
          description: Limit the bundle to one workflow key.
          schema:
            type: string
        - name: includeRetired
          in: query
          required: false
          description: Include RETIRED versions; defaults to false.
          schema:
            type: boolean
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - bundleFormat
                  - definitions
                properties:
                  bundleFormat:
                    type: integer
                    format: date-time
                  definitions:
                    type: array
                    items:
                      type: object
                      required:
                        - workflowKey
                        - caseTypeCode
                        - versionNumber
                        - status
                        - definition
                      properties:
                        workflowKey:
                          type: string
                        caseTypeCode:
                          type: string
                        versionNumber:
                          type: integer
                        status:
                          type: string
                          description: Current normalized lifecycle state.
                        definition:
                          type: object
                          required:
                            - schemaVersion
                            - workflowKey
                            - version
                            - caseType
                            - stages
                            - terminalOutcomes
                          properties:
                            schemaVersion:
                              type: integer
                            workflowKey:
                              type: string
                            version:
                              type: integer
                              description: Monotonically increasing resource version.
                            caseType:
                              type: string
                            stages:
                              type: array
                              items:
                                type: object
                                required:
                                  - stageKey
                                  - displayName
                                  - next
                                properties:
                                  stageKey:
                                    type: string
                                  displayName:
                                    type: string
                                  next:
                                    type: array
                                    items:
                                      type: object
                                      required:
                                        - when
                                        - stage
                                      properties:
                                        when:
                                          type: string
                                        stage:
                                          type: string
                            terminalOutcomes:
                              type: array
                              items:
                                type: object
              example:
                bundleFormat: 1
                definitions:
                  - workflowKey: COLLECTIONS_DEFAULT
                    caseTypeCode: COLLECTIONS
                    versionNumber: 2
                    status: ACTIVE
                    definition:
                      schemaVersion: 2
                      workflowKey: COLLECTIONS_DEFAULT
                      version: 2
                      caseType: COLLECTIONS
                      stages:
                        - stageKey: INTAKE
                          displayName: Understand the case
                          next:
                            - when: DEFAULT
                              stage: CLOSE
                        - stageKey: CLOSE
                          displayName: Close the case
                          terminal: true
                      terminalOutcomes: []
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
  /v1/servicing/admin/workflow-definitions/import:
    post:
      tags:
        - Workflow administration
      operationId: importWorkflowDefinitions
      summary: Import a definition bundle
      description: Imports an exported bundle. Versions identical to a stored one are skipped, changed definitions become new
        drafts, and per-definition errors are reported without failing the batch.
      x-permission: ADMIN_SERVICING_WORKFLOW_DEFINITION
      x-idempotent: true
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: Idempotency-Key
          in: header
          required: false
          description: Optional replay key for this logical mutation. Omission creates a fresh server-owned key for this attempt;
            blank, repeated, or longer-than-50-character values are rejected.
          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:
                      - operation
                      - results
                    properties:
                      operation:
                        type: string
                      results:
                        type: array
                        items:
                          type: object
                          required:
                            - workflowKey
                            - outcome
                            - versionNumber
                          properties:
                            workflowKey:
                              type: string
                            outcome:
                              type: string
                            versionNumber:
                              type: integer
              example:
                resourceId: 0
                changes:
                  operation: IMPORT
                  results:
                    - workflowKey: COLLECTIONS_DEFAULT
                      outcome: CREATED_DRAFT
                      versionNumber: 3
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
        "409":
          $ref: "#/components/responses/Servicing409Error"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - bundle
                - reason
              properties:
                bundle:
                  type: object
                  required:
                    - definitions
                  properties:
                    definitions:
                      type: array
                      items:
                        type: object
                        required:
                          - workflowKey
                          - caseTypeCode
                          - definition
                        properties:
                          workflowKey:
                            type: string
                          caseTypeCode:
                            type: string
                          definition:
                            type: object
                            required:
                              - schemaVersion
                              - stages
                              - terminalOutcomes
                            properties:
                              schemaVersion:
                                type: integer
                              stages:
                                type: array
                                items:
                                  type: object
                                  required:
                                    - stageKey
                                    - displayName
                                    - next
                                  properties:
                                    stageKey:
                                      type: string
                                    displayName:
                                      type: string
                                    next:
                                      type: array
                                      items:
                                        type: object
                                        required:
                                          - when
                                          - stage
                                        properties:
                                          when:
                                            type: string
                                          stage:
                                            type: string
                              terminalOutcomes:
                                type: array
                                items:
                                  type: object
                reason:
                  type: string
              example:
                bundle:
                  definitions:
                    - workflowKey: COLLECTIONS_DEFAULT
                      caseTypeCode: COLLECTIONS
                      definition:
                        schemaVersion: 2
                        stages:
                          - stageKey: INTAKE
                            displayName: Understand the case
                            next:
                              - when: DEFAULT
                                stage: CLOSE
                          - stageKey: CLOSE
                            displayName: Close the case
                            terminal: true
                        terminalOutcomes: []
                reason: Promote the reviewed definitions from staging.
            example:
              bundle:
                definitions:
                  - workflowKey: COLLECTIONS_DEFAULT
                    caseTypeCode: COLLECTIONS
                    definition:
                      schemaVersion: 2
                      stages:
                        - stageKey: INTAKE
                          displayName: Understand the case
                          next:
                            - when: DEFAULT
                              stage: CLOSE
                        - stageKey: CLOSE
                          displayName: Close the case
                          terminal: true
                      terminalOutcomes: []
              reason: Promote the reviewed definitions from staging.
  /v1/servicing/admin/workflow-definitions/validate:
    post:
      tags:
        - Workflow administration
      operationId: validateWorkflowDefinition
      summary: Validate a definition without saving
      description: "Stateless dry-run for the builder: schema violations and reference findings return as one findings list
        anchored to stages best-effort. Nothing is persisted or audited."
      x-permission: READ_SERVICING_WORKFLOW_DEFINITION
      x-idempotent: true
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: Idempotency-Key
          in: header
          required: false
          description: Optional replay key for this logical mutation. Omission creates a fresh server-owned key for this attempt;
            blank, repeated, or longer-than-50-character values are rejected.
          schema:
            type: string
            minLength: 1
            maxLength: 50
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - valid
                  - findings
                properties:
                  valid:
                    type: boolean
                  findings:
                    type: array
                    items:
                      type: object
                      required:
                        - severity
                        - code
                        - message
                        - stageKey
                      properties:
                        severity:
                          type: string
                        code:
                          type: string
                        message:
                          type: string
                        stageKey:
                          type: string
              example:
                valid: false
                findings:
                  - severity: ERROR
                    code: TASK_TYPE_UNKNOWN
                    message: taskTemplate FIELD_VISIT names a task type that does not exist
                    stageKey: MONITORING
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
        "409":
          $ref: "#/components/responses/Servicing409Error"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - caseTypeCode
                - definition
              properties:
                caseTypeCode:
                  type: string
                workflowKey:
                  type: string
                versionNumber:
                  type: integer
                definition:
                  type: object
                  required:
                    - schemaVersion
                    - stages
                    - terminalOutcomes
                  properties:
                    schemaVersion:
                      type: integer
                    stages:
                      type: array
                      items:
                        type: object
                        required:
                          - stageKey
                          - displayName
                          - next
                        properties:
                          stageKey:
                            type: string
                          displayName:
                            type: string
                          next:
                            type: array
                            items:
                              type: object
                              required:
                                - when
                                - stage
                              properties:
                                when:
                                  type: string
                                stage:
                                  type: string
                    terminalOutcomes:
                      type: array
                      items:
                        type: object
              example:
                caseTypeCode: COLLECTIONS
                workflowKey: COLLECTIONS_DEFAULT
                versionNumber: 3
                definition:
                  schemaVersion: 2
                  stages:
                    - stageKey: INTAKE
                      displayName: Understand the case
                      next:
                        - when: DEFAULT
                          stage: CLOSE
                    - stageKey: CLOSE
                      displayName: Close the case
                      terminal: true
                  terminalOutcomes: []
            example:
              caseTypeCode: COLLECTIONS
              workflowKey: COLLECTIONS_DEFAULT
              versionNumber: 3
              definition:
                schemaVersion: 2
                stages:
                  - stageKey: INTAKE
                    displayName: Understand the case
                    next:
                      - when: DEFAULT
                        stage: CLOSE
                  - stageKey: CLOSE
                    displayName: Close the case
                    terminal: true
                terminalOutcomes: []
  /v1/servicing/admin/workflow-definitions/{workflowKey}:
    get:
      tags:
        - Workflow administration
      operationId: getWorkflowDefinition
      summary: Read a workflow key overview
      description: Returns every version of one key with its lifecycle detail, plus which enabled reasons and type defaults
        currently resolve to the key.
      x-permission: READ_SERVICING_WORKFLOW_DEFINITION
      x-idempotent: false
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: workflowKey
          in: path
          required: true
          description: Stable opaque workflowKey identifier.
          schema:
            type: string
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - workflowKey
                  - caseTypeCode
                  - caseTypeDisplayName
                  - activeVersion
                  - versions
                  - resolvedBy
                properties:
                  workflowKey:
                    type: string
                  caseTypeCode:
                    type: string
                  caseTypeDisplayName:
                    type: string
                  activeVersion:
                    type: integer
                  versions:
                    type: array
                    items:
                      type: object
                      required:
                        - versionNumber
                        - status
                        - discarded
                        - rowVersion
                        - activatedAt
                        - stageCount
                        - openPinnedCases
                      properties:
                        versionNumber:
                          type: integer
                        status:
                          type: string
                          description: Current normalized lifecycle state.
                        discarded:
                          type: boolean
                        rowVersion:
                          type: integer
                        activatedAt:
                          type: string
                          format: date-time
                        stageCount:
                          type: integer
                        openPinnedCases:
                          type: integer
                  resolvedBy:
                    type: object
                    required:
                      - reasons
                      - defaultOfTypes
                    properties:
                      reasons:
                        type: array
                        items:
                          type: object
                          required:
                            - caseTypeCode
                            - reasonCode
                          properties:
                            caseTypeCode:
                              type: string
                            reasonCode:
                              type: string
                              description: Configured structured reason code.
                      defaultOfTypes:
                        type: array
                        items:
                          type: string
              example:
                workflowKey: COLLECTIONS_DEFAULT
                caseTypeCode: COLLECTIONS
                caseTypeDisplayName: Collections
                activeVersion: 2
                versions:
                  - versionNumber: 2
                    status: ACTIVE
                    discarded: false
                    rowVersion: 5
                    activatedAt: 2026-07-20T12:00:00Z
                    stageCount: 4
                    openPinnedCases: 12
                  - versionNumber: 3
                    status: DRAFT
                    discarded: false
                    rowVersion: 1
                    stageCount: 4
                    openPinnedCases: 0
                resolvedBy:
                  reasons:
                    - caseTypeCode: COLLECTIONS
                      reasonCode: DELINQUENCY_SIGNAL
                  defaultOfTypes:
                    - COLLECTIONS
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
  /v1/servicing/admin/workflow-definitions/{workflowKey}/versions/{versionNumber}:
    get:
      tags:
        - Workflow administration
      operationId: getWorkflowDefinitionVersion
      summary: Read one definition version
      description: Returns the raw definition body of one version — not the worker-safe projection — with its status, row
        version, lifecycle timestamps, and open pinned-case count.
      x-permission: READ_SERVICING_WORKFLOW_DEFINITION
      x-idempotent: false
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: workflowKey
          in: path
          required: true
          description: Stable opaque workflowKey identifier.
          schema:
            type: string
        - name: versionNumber
          in: path
          required: true
          description: Stable opaque versionNumber identifier.
          schema:
            type: string
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - workflowKey
                  - caseTypeCode
                  - versionNumber
                  - status
                  - discarded
                  - rowVersion
                  - activatedAt
                  - openPinnedCases
                  - definition
                properties:
                  workflowKey:
                    type: string
                  caseTypeCode:
                    type: string
                  versionNumber:
                    type: integer
                  status:
                    type: string
                    description: Current normalized lifecycle state.
                  discarded:
                    type: boolean
                  rowVersion:
                    type: integer
                  activatedAt:
                    type: string
                    format: date-time
                  openPinnedCases:
                    type: integer
                  definition:
                    type: object
                    required:
                      - schemaVersion
                      - workflowKey
                      - version
                      - caseType
                      - stages
                      - terminalOutcomes
                    properties:
                      schemaVersion:
                        type: integer
                      workflowKey:
                        type: string
                      version:
                        type: integer
                        description: Monotonically increasing resource version.
                      caseType:
                        type: string
                      stages:
                        type: array
                        items:
                          type: object
                          required:
                            - stageKey
                            - displayName
                            - next
                          properties:
                            stageKey:
                              type: string
                            displayName:
                              type: string
                            next:
                              type: array
                              items:
                                type: object
                                required:
                                  - when
                                  - stage
                                properties:
                                  when:
                                    type: string
                                  stage:
                                    type: string
                      terminalOutcomes:
                        type: array
                        items:
                          type: object
              example:
                workflowKey: COLLECTIONS_DEFAULT
                caseTypeCode: COLLECTIONS
                versionNumber: 2
                status: ACTIVE
                discarded: false
                rowVersion: 5
                activatedAt: 2026-07-20T12:00:00Z
                openPinnedCases: 12
                definition:
                  schemaVersion: 2
                  workflowKey: COLLECTIONS_DEFAULT
                  version: 2
                  caseType: COLLECTIONS
                  stages:
                    - stageKey: INTAKE
                      displayName: Understand the case
                      next:
                        - when: DEFAULT
                          stage: CLOSE
                    - stageKey: CLOSE
                      displayName: Close the case
                      terminal: true
                  terminalOutcomes: []
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
    put:
      tags:
        - Workflow administration
      operationId: updateWorkflowDefinitionDraft
      summary: Replace a draft definition
      description: Replaces the body of a DRAFT version after parsing and reference validation; only drafts can be edited.
        expectedVersion refuses the write when the row changed since it was read.
      x-permission: ADMIN_SERVICING_WORKFLOW_DEFINITION
      x-idempotent: true
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: workflowKey
          in: path
          required: true
          description: Stable opaque workflowKey identifier.
          schema:
            type: string
        - name: versionNumber
          in: path
          required: true
          description: Stable opaque versionNumber identifier.
          schema:
            type: string
        - name: Idempotency-Key
          in: header
          required: false
          description: Optional replay key for this logical mutation. Omission creates a fresh server-owned key for this attempt;
            blank, repeated, or longer-than-50-character values are rejected.
          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:
                      - operation
                      - workflowKey
                      - versionNumber
                    properties:
                      operation:
                        type: string
                      workflowKey:
                        type: string
                      versionNumber:
                        type: integer
              example:
                resourceId: 3
                changes:
                  operation: UPDATE_DRAFT
                  workflowKey: COLLECTIONS_DEFAULT
                  versionNumber: 3
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
        "409":
          $ref: "#/components/responses/Servicing409Error"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - definition
                - reason
              properties:
                definition:
                  type: object
                  required:
                    - schemaVersion
                    - stages
                    - terminalOutcomes
                  properties:
                    schemaVersion:
                      type: integer
                    stages:
                      type: array
                      items:
                        type: object
                        required:
                          - stageKey
                          - displayName
                          - next
                        properties:
                          stageKey:
                            type: string
                          displayName:
                            type: string
                          next:
                            type: array
                            items:
                              type: object
                              required:
                                - when
                                - stage
                              properties:
                                when:
                                  type: string
                                stage:
                                  type: string
                    terminalOutcomes:
                      type: array
                      items:
                        type: object
                expectedVersion:
                  type: integer
                reason:
                  type: string
              example:
                definition:
                  schemaVersion: 2
                  stages:
                    - stageKey: INTAKE
                      displayName: Understand the case
                      next:
                        - when: DEFAULT
                          stage: CLOSE
                    - stageKey: CLOSE
                      displayName: Close the case
                      terminal: true
                  terminalOutcomes: []
                expectedVersion: 1
                reason: Tighten the monitoring branch.
            example:
              definition:
                schemaVersion: 2
                stages:
                  - stageKey: INTAKE
                    displayName: Understand the case
                    next:
                      - when: DEFAULT
                        stage: CLOSE
                  - stageKey: CLOSE
                    displayName: Close the case
                    terminal: true
                terminalOutcomes: []
              expectedVersion: 1
              reason: Tighten the monitoring branch.
  /v1/servicing/admin/workflow-definitions/{workflowKey}/versions:
    post:
      tags:
        - Workflow administration
      operationId: createWorkflowDefinitionVersion
      summary: Draft the next version
      description: Drafts the next version of an existing key from a supplied definition, a named base version, or the current
        ACTIVE version by default. Versions of one key never drift across case types.
      x-permission: ADMIN_SERVICING_WORKFLOW_DEFINITION
      x-idempotent: true
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: workflowKey
          in: path
          required: true
          description: Stable opaque workflowKey identifier.
          schema:
            type: string
        - name: Idempotency-Key
          in: header
          required: false
          description: Optional replay key for this logical mutation. Omission creates a fresh server-owned key for this attempt;
            blank, repeated, or longer-than-50-character values are rejected.
          schema:
            type: string
            minLength: 1
            maxLength: 50
      responses:
        "201":
          description: Created.
          content:
            application/json:
              schema:
                type: object
                required:
                  - resourceId
                  - changes
                properties:
                  resourceId:
                    type: integer
                  changes:
                    type: object
                    required:
                      - operation
                      - workflowKey
                      - versionNumber
                    properties:
                      operation:
                        type: string
                      workflowKey:
                        type: string
                      versionNumber:
                        type: integer
              example:
                resourceId: 42
                changes:
                  operation: DRAFT
                  workflowKey: COLLECTIONS_DEFAULT
                  versionNumber: 3
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
        "409":
          $ref: "#/components/responses/Servicing409Error"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - reason
              properties:
                basedOnVersion:
                  type: integer
                reason:
                  type: string
              example:
                basedOnVersion: 2
                reason: Draft the next collections revision.
            example:
              basedOnVersion: 2
              reason: Draft the next collections revision.
  /v1/servicing/admin/workflow-definitions/{workflowKey}/versions/{versionNumber}/activate:
    post:
      tags:
        - Workflow administration
      operationId: activateWorkflowDefinitionVersion
      summary: Activate a definition version
      description: Puts a version into force for new cases of the type under a separate promotion authority, returning
        warnings for stage keys dropped from the current ACTIVE version and for declared evidence or approval gates.
      x-permission: ACTIVATE_SERVICING_WORKFLOW_DEFINITION
      x-idempotent: true
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: workflowKey
          in: path
          required: true
          description: Stable opaque workflowKey identifier.
          schema:
            type: string
        - name: versionNumber
          in: path
          required: true
          description: Stable opaque versionNumber identifier.
          schema:
            type: string
        - name: Idempotency-Key
          in: header
          required: false
          description: Optional replay key for this logical mutation. Omission creates a fresh server-owned key for this attempt;
            blank, repeated, or longer-than-50-character values are rejected.
          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:
                      - operation
                      - workflowKey
                      - versionNumber
                      - warnings
                    properties:
                      operation:
                        type: string
                      workflowKey:
                        type: string
                      versionNumber:
                        type: integer
                      warnings:
                        type: array
                        items:
                          type: string
              example:
                resourceId: 3
                changes:
                  operation: ACTIVATE
                  workflowKey: COLLECTIONS_DEFAULT
                  versionNumber: 3
                  warnings:
                    - "Stage keys dropped from the current ACTIVE version: FIELD_REVIEW"
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
        "409":
          $ref: "#/components/responses/Servicing409Error"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - reason
              properties:
                expectedVersion:
                  type: integer
                reason:
                  type: string
              example:
                expectedVersion: 2
                reason: Promote the tightened monitoring flow.
            example:
              expectedVersion: 2
              reason: Promote the tightened monitoring flow.
  /v1/servicing/admin/workflow-definitions/{workflowKey}/versions/{versionNumber}/discard:
    post:
      tags:
        - Workflow administration
      operationId: discardWorkflowDefinitionVersion
      summary: Discard a draft version
      description: Discards a DRAFT version that will not be promoted. expectedVersion refuses the discard when the row
        changed since it was read.
      x-permission: ADMIN_SERVICING_WORKFLOW_DEFINITION
      x-idempotent: true
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: workflowKey
          in: path
          required: true
          description: Stable opaque workflowKey identifier.
          schema:
            type: string
        - name: versionNumber
          in: path
          required: true
          description: Stable opaque versionNumber identifier.
          schema:
            type: string
        - name: Idempotency-Key
          in: header
          required: false
          description: Optional replay key for this logical mutation. Omission creates a fresh server-owned key for this attempt;
            blank, repeated, or longer-than-50-character values are rejected.
          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:
                      - operation
                      - workflowKey
                      - versionNumber
                    properties:
                      operation:
                        type: string
                      workflowKey:
                        type: string
                      versionNumber:
                        type: integer
              example:
                resourceId: 3
                changes:
                  operation: DISCARD
                  workflowKey: COLLECTIONS_DEFAULT
                  versionNumber: 3
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
        "409":
          $ref: "#/components/responses/Servicing409Error"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - reason
              properties:
                expectedVersion:
                  type: integer
                reason:
                  type: string
              example:
                expectedVersion: 2
                reason: Superseded by the merged revision.
            example:
              expectedVersion: 2
              reason: Superseded by the merged revision.
  /v1/servicing/admin/workflow-definitions/{workflowKey}/versions/{versionNumber}/retire:
    post:
      tags:
        - Workflow administration
      operationId: retireWorkflowDefinitionVersion
      summary: Retire a definition version
      description: Retires a version under the promotion authority. Retiring the ACTIVE version is refused while enabled case
        types or reasons would still resolve to the key with no replacement.
      x-permission: ACTIVATE_SERVICING_WORKFLOW_DEFINITION
      x-idempotent: true
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: workflowKey
          in: path
          required: true
          description: Stable opaque workflowKey identifier.
          schema:
            type: string
        - name: versionNumber
          in: path
          required: true
          description: Stable opaque versionNumber identifier.
          schema:
            type: string
        - name: Idempotency-Key
          in: header
          required: false
          description: Optional replay key for this logical mutation. Omission creates a fresh server-owned key for this attempt;
            blank, repeated, or longer-than-50-character values are rejected.
          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:
                      - operation
                      - workflowKey
                      - versionNumber
                    properties:
                      operation:
                        type: string
                      workflowKey:
                        type: string
                      versionNumber:
                        type: integer
              example:
                resourceId: 2
                changes:
                  operation: RETIRE
                  workflowKey: COLLECTIONS_DEFAULT
                  versionNumber: 2
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
        "409":
          $ref: "#/components/responses/Servicing409Error"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - reason
              properties:
                expectedVersion:
                  type: integer
                reason:
                  type: string
              example:
                expectedVersion: 5
                reason: Collections flow replaced by version 3.
            example:
              expectedVersion: 5
              reason: Collections flow replaced by version 3.
  /v1/servicing/portal-agreements:
    get:
      tags:
        - Portal contracts
      operationId: listPortalAgreements
      summary: List borrower agreements
      description: Lists the customer hardship agreements newest first, projected from the exact display bindings the issued
        document quoted. Without a state filter only borrower-visible statuses are returned.
      x-permission: READ_PORTAL_AGREEMENT
      x-idempotent: false
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: customerRef
          in: query
          required: false
          description: Customer reference the listing is scoped to.
          schema:
            type: string
        - name: state
          in: query
          required: false
          description: Exact agreement status filter.
          schema:
            type: string
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - items
                properties:
                  items:
                    type: array
                    items:
                      type: object
                      required:
                        - agreementRef
                        - loanRef
                        - kind
                        - title
                        - status
                        - publishedAt
                        - expiresAt
                        - viewedAt
                        - respondedAt
                        - documentDigest
                        - termsSummary
                      properties:
                        agreementRef:
                          type: string
                        loanRef:
                          type: string
                        kind:
                          type: string
                        title:
                          type: string
                        status:
                          type: string
                          description: Current normalized lifecycle state.
                        publishedAt:
                          type: string
                          format: date-time
                        expiresAt:
                          type: string
                          format: date-time
                        viewedAt:
                          type: string
                          format: date-time
                        respondedAt:
                          type: string
                          format: date-time
                        documentDigest:
                          type: string
                        termsSummary:
                          type: object
                          required:
                            - deferredPaymentCount
                            - deferredTotal
                            - resumptionDate
                            - currentMaturity
                            - proposedMaturity
                            - totalCostChange
                            - affectedDueDates
                          properties:
                            deferredPaymentCount:
                              type: integer
                            deferredTotal:
                              type: string
                            resumptionDate:
                              type: string
                              format: date
                            currentMaturity:
                              type: string
                            proposedMaturity:
                              type: string
                            totalCostChange:
                              type: string
                            affectedDueDates:
                              type: array
                              items:
                                type: string
              example:
                items:
                  - agreementRef: LE-OFR-9001
                    loanRef: "456"
                    kind: HARDSHIP_REPLACEMENT_AGREEMENT
                    title: Payment pause agreement
                    status: SENT
                    publishedAt: 2026-07-25T18:40:00Z
                    expiresAt: 2026-08-04T18:40:00Z
                    viewedAt: null
                    respondedAt: null
                    documentDigest: 2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824
                    termsSummary:
                      deferredPaymentCount: 3
                      deferredTotal: 1,502.85
                      resumptionDate: 2026-11-01
                      currentMaturity: 2028-07-01
                      proposedMaturity: 2028-10-01
                      totalCostChange: "48.60"
                      affectedDueDates:
                        - 2026-08-01
                        - 2026-09-01
                        - 2026-10-01
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
  /v1/servicing/portal-agreements/{agreementRef}:
    get:
      tags:
        - Portal contracts
      operationId: getPortalAgreement
      summary: Retrieve one agreement
      description: Returns the borrower-safe projection of one agreement, including the document digest that a later
        acceptance must bind to.
      x-permission: READ_PORTAL_AGREEMENT
      x-idempotent: false
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: agreementRef
          in: path
          required: true
          description: Stable opaque agreementRef identifier.
          schema:
            type: string
        - name: customerRef
          in: query
          required: false
          description: Customer the agreement is addressed to; the read is scoped to this customer.
          schema:
            type: string
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - agreementRef
                  - loanRef
                  - kind
                  - title
                  - status
                  - publishedAt
                  - expiresAt
                  - viewedAt
                  - respondedAt
                  - documentDigest
                  - termsSummary
                properties:
                  agreementRef:
                    type: string
                  loanRef:
                    type: string
                  kind:
                    type: string
                  title:
                    type: string
                  status:
                    type: string
                    description: Current normalized lifecycle state.
                  publishedAt:
                    type: string
                    format: date-time
                  expiresAt:
                    type: string
                    format: date-time
                  viewedAt:
                    type: string
                    format: date-time
                  respondedAt:
                    type: string
                    format: date-time
                  documentDigest:
                    type: string
                  termsSummary:
                    type: object
                    required:
                      - deferredPaymentCount
                      - deferredTotal
                      - resumptionDate
                      - currentMaturity
                      - proposedMaturity
                      - totalCostChange
                      - affectedDueDates
                    properties:
                      deferredPaymentCount:
                        type: integer
                      deferredTotal:
                        type: string
                      resumptionDate:
                        type: string
                        format: date
                      currentMaturity:
                        type: string
                      proposedMaturity:
                        type: string
                      totalCostChange:
                        type: string
                      affectedDueDates:
                        type: array
                        items:
                          type: string
              example:
                agreementRef: LE-OFR-9001
                loanRef: "456"
                kind: HARDSHIP_REPLACEMENT_AGREEMENT
                title: Payment pause agreement
                status: VIEWED
                publishedAt: 2026-07-25T18:40:00Z
                expiresAt: 2026-08-04T18:40:00Z
                viewedAt: 2026-07-25T18:45:00Z
                respondedAt: null
                documentDigest: 2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824
                termsSummary:
                  deferredPaymentCount: 3
                  deferredTotal: 1,502.85
                  resumptionDate: 2026-11-01
                  currentMaturity: 2028-07-01
                  proposedMaturity: 2028-10-01
                  totalCostChange: "48.60"
                  affectedDueDates:
                    - 2026-08-01
                    - 2026-09-01
                    - 2026-10-01
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
  /v1/servicing/portal-agreements/{agreementRef}/viewed:
    post:
      tags:
        - Portal contracts
      operationId: markPortalAgreementViewed
      summary: Record that an agreement was viewed
      description: Records the borrower opening her agreement, moving SENT or DELIVERY_UNKNOWN offers to VIEWED. Always
        answers 200 because the signal is telemetry; transitioned reports whether the status actually moved.
      x-permission: RECORD_PORTAL_AGREEMENT_RESPONSE
      x-idempotent: true
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: agreementRef
          in: path
          required: true
          description: Stable opaque agreementRef identifier.
          schema:
            type: string
        - name: customerRef
          in: query
          required: false
          description: Customer the agreement is addressed to.
          schema:
            type: string
        - name: Idempotency-Key
          in: header
          required: false
          description: Optional replay key for this logical mutation. Omission creates a fresh server-owned key for this attempt;
            blank, repeated, or longer-than-50-character values are rejected.
          schema:
            type: string
            minLength: 1
            maxLength: 50
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - acknowledged
                  - transitioned
                properties:
                  acknowledged:
                    type: boolean
                  transitioned:
                    type: boolean
              example:
                acknowledged: true
                transitioned: true
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
        "409":
          $ref: "#/components/responses/Servicing409Error"
  /v1/servicing/portal-agreements/{agreementRef}/acceptance:
    post:
      tags:
        - Portal contracts
      operationId: acceptPortalAgreement
      summary: Accept an agreement
      description: Records the borrower signature after checking status, expiry, document digest, and signer, then starts
        execution of the bound reschedule. executionState is EXECUTING when execution is queued and INVALIDATED when the
        loan drifted since pricing; refusals return 409 codes such as offer.superseded, offer.expired,
        agreement.digest_mismatch, and offer.signer_mismatch.
      x-permission: RECORD_PORTAL_AGREEMENT_RESPONSE
      x-idempotent: true
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: agreementRef
          in: path
          required: true
          description: Stable opaque agreementRef identifier.
          schema:
            type: string
        - name: customerRef
          in: query
          required: false
          description: Customer the agreement is addressed to.
          schema:
            type: string
        - name: Idempotency-Key
          in: header
          required: false
          description: Optional replay key for this logical mutation. Omission creates a fresh server-owned key for this attempt;
            blank, repeated, or longer-than-50-character values are rejected.
          schema:
            type: string
            minLength: 1
            maxLength: 50
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - acceptanceId
                  - executionState
                  - invalidationReason
                properties:
                  acceptanceId:
                    type: string
                  executionState:
                    type: string
                  invalidationReason:
                    type: string
              example:
                acceptanceId: LE-ACC-9001
                executionState: EXECUTING
                invalidationReason: null
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
        "409":
          $ref: "#/components/responses/Servicing409Error"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - signerCustomerRef
                - documentDigest
                - evidenceRef
              properties:
                signerCustomerRef:
                  type: string
                documentDigest:
                  type: string
                evidenceRef:
                  type: string
              example:
                signerCustomerRef: "123"
                documentDigest: 2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824
                evidenceRef: portal-consent-9001-123
            example:
              signerCustomerRef: "123"
              documentDigest: 2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824
              evidenceRef: portal-consent-9001-123
  /v1/servicing/portal-agreements/{agreementRef}/decline:
    post:
      tags:
        - Portal contracts
      operationId: declinePortalAgreement
      summary: Decline an agreement
      description: Records the borrower declining her live offer under the same recorded signer identity. Superseded offers
        and mismatched signers return 409.
      x-permission: RECORD_PORTAL_AGREEMENT_RESPONSE
      x-idempotent: true
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: agreementRef
          in: path
          required: true
          description: Stable opaque agreementRef identifier.
          schema:
            type: string
        - name: customerRef
          in: query
          required: false
          description: Customer the agreement is addressed to.
          schema:
            type: string
        - name: Idempotency-Key
          in: header
          required: false
          description: Optional replay key for this logical mutation. Omission creates a fresh server-owned key for this attempt;
            blank, repeated, or longer-than-50-character values are rejected.
          schema:
            type: string
            minLength: 1
            maxLength: 50
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - acknowledged
                properties:
                  acknowledged:
                    type: boolean
              example:
                acknowledged: true
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
        "409":
          $ref: "#/components/responses/Servicing409Error"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - signerCustomerRef
              properties:
                signerCustomerRef:
                  type: string
                note:
                  type: string
              example:
                signerCustomerRef: "123"
                note: I can resume normal payments next month.
            example:
              signerCustomerRef: "123"
              note: I can resume normal payments next month.
  /v1/servicing/portal-agreements/{agreementRef}/change-requests:
    post:
      tags:
        - Portal contracts
      operationId: requestPortalAgreementChange
      summary: Ask for different terms
      description: Records a structured request for different terms and moves the live offer to UNDER_CHANGE_REVIEW. No terms
        are returned; policy and human approval decide what is offerable.
      x-permission: RECORD_PORTAL_AGREEMENT_RESPONSE
      x-idempotent: true
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: agreementRef
          in: path
          required: true
          description: Stable opaque agreementRef identifier.
          schema:
            type: string
        - name: customerRef
          in: query
          required: false
          description: Customer the agreement is addressed to.
          schema:
            type: string
        - name: Idempotency-Key
          in: header
          required: false
          description: Optional replay key for this logical mutation. Omission creates a fresh server-owned key for this attempt;
            blank, repeated, or longer-than-50-character values are rejected.
          schema:
            type: string
            minLength: 1
            maxLength: 50
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - acknowledged
                properties:
                  acknowledged:
                    type: boolean
              example:
                acknowledged: true
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
        "409":
          $ref: "#/components/responses/Servicing409Error"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - requestedDeferredPayments
              properties:
                requestedDeferredPayments:
                  type: integer
                note:
                  type: string
              example:
                requestedDeferredPayments: 5
                note: Two more months of pause would let me recover.
            example:
              requestedDeferredPayments: 5
              note: Two more months of pause would let me recover.
  /v1/servicing/portal-documents:
    get:
      tags:
        - Portal contracts
      operationId: listPortalDocuments
      summary: List borrower uploads
      description: Lists the customer borrower-uploaded documents, including items still pending review. available reports
        whether scan-clean content can be downloaded yet.
      x-permission: READ_PORTAL_BORROWER_DOCUMENT
      x-idempotent: false
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: customerRef
          in: query
          required: true
          description: Customer whose uploads are listed.
          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
                        - evidenceType
                        - title
                        - fileName
                        - uploadedAt
                        - reviewState
                        - available
                      properties:
                        documentId:
                          type: integer
                        documentRef:
                          type: string
                        evidenceType:
                          type: string
                        title:
                          type: string
                        fileName:
                          type: string
                        uploadedAt:
                          type: string
                          format: date-time
                        reviewState:
                          type: string
                        available:
                          type: boolean
              example:
                items:
                  - documentId: 7001
                    documentRef: LE-DOC-7001
                    evidenceType: MEDICAL_CERTIFICATE
                    title: Doctors letter June 2026
                    fileName: doctors-letter.pdf
                    uploadedAt: 2026-07-25T18:40:00Z
                    reviewState: PENDING_REVIEW
                    available: true
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
  /v1/servicing/portal-documents/{documentId}/content:
    get:
      tags:
        - Portal contracts
      operationId: getPortalDocumentContent
      summary: Create a borrower document download
      description: Returns a short-lived, no-store download envelope for one of the customer's own scan-clean uploads.
        Ownership is part of the query, so anything else answers 404.
      x-permission: READ_PORTAL_BORROWER_DOCUMENT
      x-idempotent: false
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: documentId
          in: path
          required: true
          description: Positive numeric document identifier.
          schema:
            type: integer
            format: int64
            minimum: 1
        - name: customerRef
          in: query
          required: true
          description: Customer who owns the upload.
          schema:
            type: string
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - downloadUrl
                  - expiresAt
                  - fileName
                  - contentType
                  - checksumSha256
                properties:
                  downloadUrl:
                    type: string
                  expiresAt:
                    type: string
                    format: date-time
                  fileName:
                    type: string
                  contentType:
                    type: string
                  checksumSha256:
                    type: string
              example:
                downloadUrl: https://content.example/opaque-signed-token
                expiresAt: 2026-07-25T18:45:00Z
                fileName: doctors-letter.pdf
                contentType: application/pdf
                checksumSha256: 2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
  /v1/servicing/portal-document-invitations:
    get:
      tags:
        - Portal contracts
      operationId: listPortalDocumentInvitations
      summary: List open document requests
      description: Lists the customer's upload invitations with the same per-evidence-type instructions the emailed link page
        shows. Defaults to the actionable states ISSUED, DELIVERED, and OPENED.
      x-permission: READ_PORTAL_DOCUMENT_INVITATION
      x-idempotent: false
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: customerRef
          in: query
          required: true
          description: Customer whose invitations are listed.
          schema:
            type: string
        - name: state
          in: query
          required: false
          description: Exact invitation state filter.
          schema:
            type: string
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - items
                properties:
                  items:
                    type: array
                    items:
                      type: object
                      required:
                        - invitationRef
                        - evidenceType
                        - state
                        - issuedAt
                        - expiresAt
                        - uploadsRemaining
                        - title
                        - mustShow
                        - doNotSend
                        - privacyNote
                        - acceptedFormats
                        - maxBytes
                      properties:
                        invitationRef:
                          type: string
                        evidenceType:
                          type: string
                        state:
                          type: string
                        issuedAt:
                          type: string
                          format: date-time
                        expiresAt:
                          type: string
                          format: date-time
                        uploadsRemaining:
                          type: integer
                        title:
                          type: string
                        mustShow:
                          type: array
                          items:
                            type: string
                        doNotSend:
                          type: array
                          items:
                            type: string
                        privacyNote:
                          type: string
                        acceptedFormats:
                          type: array
                          items:
                            type: string
                        maxBytes:
                          type: integer
              example:
                items:
                  - invitationRef: LE-UPL-6001
                    evidenceType: MEDICAL_CERTIFICATE
                    state: DELIVERED
                    issuedAt: 2026-07-25T18:40:00Z
                    expiresAt: 2026-08-01T18:40:00Z
                    uploadsRemaining: 3
                    title: Please send us your doctor's letter
                    mustShow:
                      - Your name
                      - That you are currently unable to work
                      - The date your leave started
                      - The date you are expected to return to work
                      - Your doctor's name, practice and signature
                      - The date they issued it
                    doNotSend:
                      - A diagnosis, symptoms, treatment or medication
                      - Your medical history or records
                      - An employer leave letter
                      - Disability benefit paperwork
                    privacyNote: We only need the facts listed above. Please do not send anything else.
                    acceptedFormats:
                      - PDF
                      - JPEG
                      - PNG
                    maxBytes: 10485760
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
  /v1/servicing/portal-document-invitations/{invitationRef}/portal-session:
    post:
      tags:
        - Portal contracts
      operationId: mintPortalDocumentSession
      summary: Mint an upload session
      description: Exchanges a live invitation for a short-lived upload session token for an already signed-in borrower and
        moves the invitation to OPENED. Unknown, expired, used, and foreign invitations all answer the same 404.
      x-permission: MINT_PORTAL_DOCUMENT_SESSION
      x-idempotent: true
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: invitationRef
          in: path
          required: true
          description: Stable opaque invitationRef identifier.
          schema:
            type: string
        - name: Idempotency-Key
          in: header
          required: false
          description: Optional replay key for this logical mutation. Omission creates a fresh server-owned key for this attempt;
            blank, repeated, or longer-than-50-character values are rejected.
          schema:
            type: string
            minLength: 1
            maxLength: 50
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - sessionToken
                  - expiresAt
                properties:
                  sessionToken:
                    type: string
                  expiresAt:
                    type: string
                    format: date-time
              example:
                sessionToken: <opaque-session-token>
                expiresAt: 2026-07-25T19:00:00Z
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
        "409":
          $ref: "#/components/responses/Servicing409Error"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - customerRef
              properties:
                customerRef:
                  type: string
              example:
                customerRef: "123"
            example:
              customerRef: "123"
  /v1/servicing/portal-interactions:
    post:
      tags:
        - Portal contracts
      operationId: createPortalInteraction
      summary: Record an inbound portal message
      description: Records an inbound portal message as an open CHAT interaction on the customer timeline. Idempotent on
        externalRef, so a retried create returns the existing interaction id.
      x-permission: CREATE_PORTAL_INTERACTION
      x-idempotent: true
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: Idempotency-Key
          in: header
          required: false
          description: Optional replay key for this logical mutation. Omission creates a fresh server-owned key for this attempt;
            blank, repeated, or longer-than-50-character values are rejected.
          schema:
            type: string
            minLength: 1
            maxLength: 50
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - interactionId
                properties:
                  interactionId:
                    type: integer
              example:
                interactionId: 3001
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
        "409":
          $ref: "#/components/responses/Servicing409Error"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - customerRef
                - externalRef
              properties:
                customerRef:
                  type: string
                loanRef:
                  type: string
                contentSummary:
                  type: string
                externalRef:
                  type: string
              example:
                customerRef: "123"
                loanRef: "456"
                contentSummary: Borrower asked when her next payment is due.
                externalRef: portal-conv-20260725-01
            example:
              customerRef: "123"
              loanRef: "456"
              contentSummary: Borrower asked when her next payment is due.
              externalRef: portal-conv-20260725-01
  /v1/servicing/portal-interactions/{interactionId}/close:
    post:
      tags:
        - Portal contracts
      operationId: closePortalInteraction
      summary: Close a portal interaction
      description: Marks a self-service interaction COMPLETED with an optional outcome, reason, and refreshed summary. An
        interaction that cannot be closed answers 422 with reason interaction.not_closeable.
      x-permission: CLOSE_PORTAL_INTERACTION
      x-idempotent: true
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: interactionId
          in: path
          required: true
          description: Positive numeric interaction identifier.
          schema:
            type: integer
            format: int64
            minimum: 1
        - name: Idempotency-Key
          in: header
          required: false
          description: Optional replay key for this logical mutation. Omission creates a fresh server-owned key for this attempt;
            blank, repeated, or longer-than-50-character values are rejected.
          schema:
            type: string
            minLength: 1
            maxLength: 50
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - acknowledged
                properties:
                  acknowledged:
                    type: boolean
              example:
                acknowledged: true
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
        "409":
          $ref: "#/components/responses/Servicing409Error"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - outcomeCode
                - reasonCode
                - transcriptSummary
              properties:
                outcomeCode:
                  type: string
                reasonCode:
                  type: string
                  description: Configured structured reason code.
                transcriptSummary:
                  type: string
              example:
                outcomeCode: RESOLVED
                reasonCode: QUESTION_ANSWERED
                transcriptSummary: Borrower asked about her next due date and was answered in one reply.
            example:
              outcomeCode: RESOLVED
              reasonCode: QUESTION_ANSWERED
              transcriptSummary: Borrower asked about her next due date and was answered in one reply.
  /v1/servicing/portal-interactions/{interactionId}/link-case:
    post:
      tags:
        - Portal contracts
      operationId: linkPortalInteractionToCase
      summary: Link an interaction to a case
      description: Attaches a portal-origin interaction to a case an agent opened. An interaction already linked to a
        different case answers 422 with reason interaction.already_linked.
      x-permission: LINK_PORTAL_INTERACTION
      x-idempotent: true
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: interactionId
          in: path
          required: true
          description: Positive numeric interaction identifier.
          schema:
            type: integer
            format: int64
            minimum: 1
        - name: Idempotency-Key
          in: header
          required: false
          description: Optional replay key for this logical mutation. Omission creates a fresh server-owned key for this attempt;
            blank, repeated, or longer-than-50-character values are rejected.
          schema:
            type: string
            minLength: 1
            maxLength: 50
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - acknowledged
                properties:
                  acknowledged:
                    type: boolean
              example:
                acknowledged: true
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
        "409":
          $ref: "#/components/responses/Servicing409Error"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - caseId
              properties:
                caseId:
                  type: integer
                  description: Stable opaque servicing case identifier.
              example:
                caseId: 1001
            example:
              caseId: 1001
  /v1/servicing/portal-message-tasks:
    post:
      tags:
        - Portal contracts
      operationId: createPortalMessageTask
      summary: Create a message task
      description: Creates the caseless, high-priority REPLY_TO_BORROWER_MESSAGE task that puts a borrower message in front of
        an agent, idempotent per conversationRef. stickyAgentRef is accepted as a routing hint and is not currently
        honoured.
      x-permission: CREATE_PORTAL_MESSAGE_TASK
      x-idempotent: true
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: Idempotency-Key
          in: header
          required: false
          description: Optional replay key for this logical mutation. Omission creates a fresh server-owned key for this attempt;
            blank, repeated, or longer-than-50-character values are rejected.
          schema:
            type: string
            minLength: 1
            maxLength: 50
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - taskId
                properties:
                  taskId:
                    type: integer
              example:
                taskId: 2001
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
        "409":
          $ref: "#/components/responses/Servicing409Error"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - conversationRef
                - customerRef
              properties:
                conversationRef:
                  type: string
                customerRef:
                  type: string
                interactionRef:
                  type: integer
                topic:
                  type: string
                loanRef:
                  type: string
                stickyAgentRef:
                  type: string
              example:
                conversationRef: portal-conv-20260725-01
                customerRef: "123"
                interactionRef: 3001
                topic: payment due date
                loanRef: "456"
                stickyAgentRef: "4101"
            example:
              conversationRef: portal-conv-20260725-01
              customerRef: "123"
              interactionRef: 3001
              topic: payment due date
              loanRef: "456"
              stickyAgentRef: "4101"
  /v1/servicing/portal-message-tasks/{taskId}:
    get:
      tags:
        - Portal contracts
      operationId: getPortalMessageTask
      summary: Retrieve a message task
      description: Returns the safe, string-projected view of one portal message task and carries no borrower content. Ids
        belonging to other task types answer 404 rather than 403.
      x-permission: READ_PORTAL_MESSAGE_TASK
      x-idempotent: false
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: taskId
          in: path
          required: true
          description: Positive numeric task identifier.
          schema:
            type: integer
            format: int64
            minimum: 1
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - taskId
                  - status
                  - priority
                  - assignedWorkerId
                  - createdAt
                  - updatedAt
                properties:
                  taskId:
                    type: string
                  status:
                    type: string
                    description: Current normalized lifecycle state.
                  priority:
                    type: string
                  assignedWorkerId:
                    type: string
                  createdAt:
                    type: string
                    format: date-time
                  updatedAt:
                    type: string
                    format: date-time
              example:
                taskId: "2001"
                status: IN_PROGRESS
                priority: HIGH
                assignedWorkerId: "4101"
                createdAt: 2026-07-25T18:40:00Z
                updatedAt: 2026-07-25T18:45:00Z
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
  /v1/servicing/portal-message-tasks/{taskId}/activity-note:
    post:
      tags:
        - Portal contracts
      operationId: addPortalMessageTaskNote
      summary: Append an activity note
      description: Appends a BORROWER_PORTAL activity note to a portal message task and bumps its activity timestamp so a
        waiting follow-up does not sink in the queue.
      x-permission: NOTE_PORTAL_MESSAGE_TASK
      x-idempotent: true
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: taskId
          in: path
          required: true
          description: Positive numeric task identifier.
          schema:
            type: integer
            format: int64
            minimum: 1
        - name: Idempotency-Key
          in: header
          required: false
          description: Optional replay key for this logical mutation. Omission creates a fresh server-owned key for this attempt;
            blank, repeated, or longer-than-50-character values are rejected.
          schema:
            type: string
            minLength: 1
            maxLength: 50
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - acknowledged
                properties:
                  acknowledged:
                    type: boolean
              example:
                acknowledged: true
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
        "409":
          $ref: "#/components/responses/Servicing409Error"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - note
              properties:
                note:
                  type: string
              example:
                note: "Borrower replied: she can pay on the 5th."
            example:
              note: "Borrower replied: she can pay on the 5th."
  /v1/servicing/portal-message-tasks/{taskId}/release:
    post:
      tags:
        - Portal contracts
      operationId: releasePortalMessageTask
      summary: Release a message task
      description: Returns an uncompleted portal message task to AVAILABLE and clears its assignee so the next worker can pick
        it up. A task that cannot be released answers 422 with reason task.not_releasable.
      x-permission: RELEASE_PORTAL_MESSAGE_TASK
      x-idempotent: true
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: taskId
          in: path
          required: true
          description: Positive numeric task identifier.
          schema:
            type: integer
            format: int64
            minimum: 1
        - name: Idempotency-Key
          in: header
          required: false
          description: Optional replay key for this logical mutation. Omission creates a fresh server-owned key for this attempt;
            blank, repeated, or longer-than-50-character values are rejected.
          schema:
            type: string
            minLength: 1
            maxLength: 50
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - acknowledged
                properties:
                  acknowledged:
                    type: boolean
              example:
                acknowledged: true
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
        "409":
          $ref: "#/components/responses/Servicing409Error"
  /v1/servicing/portal-signals:
    get:
      tags:
        - Portal contracts
      operationId: listPortalSignals
      summary: Poll the borrower signal feed
      description: Serves the at-least-once, keyset-paged feed of borrower-relevant LMS signals, newest first, with
        allowlisted kinds and payload fields. Consumers deduplicate on signalId and pass nextCursor to continue.
      x-permission: READ_PORTAL_SIGNALS
      x-idempotent: false
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: cursor
          in: query
          required: false
          description: Opaque keyset cursor from a previous page; malformed cursors are refused.
          schema:
            type: string
        - name: limit
          in: query
          required: false
          description: Maximum items to return; defaults to 50.
          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:
                        - signalId
                        - kind
                        - customerRef
                        - loanRef
                        - occurredAt
                        - attributes
                      properties:
                        signalId:
                          type: string
                        kind:
                          type: string
                        customerRef:
                          type: string
                        loanRef:
                          type: string
                        occurredAt:
                          type: string
                          format: date-time
                        attributes:
                          type: object
                          required:
                            - status
                            - amount
                            - currency
                            - paymentId
                          properties:
                            status:
                              type: string
                              description: Current normalized lifecycle state.
                            amount:
                              type: integer
                              description: Decimal monetary value using the representation declared by this operation.
                            currency:
                              type: string
                              pattern: ^[A-Z]{3}$
                              description: ISO 4217 currency code.
                            paymentId:
                              type: integer
                  nextCursor:
                    type: string
              example:
                items:
                  - signalId: LE-SIG-88001
                    kind: PAYMENT_STATE_CHANGED
                    customerRef: "123"
                    loanRef: "456"
                    occurredAt: 2026-07-25T18:40:00Z
                    attributes:
                      status: COMPLETED
                      amount: 250
                      currency: USD
                      paymentId: 91001
                nextCursor: <opaque-keyset-cursor>
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
  /v1/servicing/cases/{caseId}/documents/invitations:
    post:
      tags:
        - Case documents
      operationId: createDocumentInvitation
      summary: Issue a borrower upload invitation
      description: Issues a single-purpose borrower upload invitation for the case; the active workflow derives the recipient,
        purpose, template, and token scope, and any live invitation for the same evidence type is superseded. The link
        secret is never returned.
      x-permission: ISSUE_SERVICING_DOCUMENT_INVITATION
      x-idempotent: true
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: caseId
          in: path
          required: true
          description: Positive numeric case identifier.
          schema:
            type: integer
            format: int64
            minimum: 1
        - name: Idempotency-Key
          in: header
          required: false
          description: Optional replay key for this logical mutation. Omission creates a fresh server-owned key for this attempt;
            blank, repeated, or longer-than-50-character values are rejected.
          schema:
            type: string
            minLength: 1
            maxLength: 50
      responses:
        "201":
          description: Created.
          content:
            application/json:
              schema:
                type: object
                required:
                  - invitationId
                  - resourceId
                  - changes
                properties:
                  invitationId:
                    type: integer
                  resourceId:
                    type: integer
                  changes:
                    type: object
                    required:
                      - invitationRef
                      - expiresAt
                      - secretDelivered
                    properties:
                      invitationRef:
                        type: string
                      expiresAt:
                        type: string
                        format: date-time
                      secretDelivered:
                        type: string
              example:
                invitationId: 6001
                resourceId: 6001
                changes:
                  invitationRef: LE-UPL-6001
                  expiresAt: 2026-08-01T18:40:00Z
                  secretDelivered: EMAIL
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
        "409":
          $ref: "#/components/responses/Servicing409Error"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - evidenceType
                - reason
              properties:
                evidenceType:
                  type: string
                reason:
                  type: string
              example:
                evidenceType: MEDICAL_CERTIFICATE
                reason: Evidence needed for the hardship review.
            example:
              evidenceType: MEDICAL_CERTIFICATE
              reason: Evidence needed for the hardship review.
  /v1/servicing/document-invitations/{invitationId}:
    get:
      tags:
        - Case documents
      operationId: getDocumentInvitation
      summary: Retrieve invitation status
      description: Returns the staff status view of one upload invitation, including lifecycle timestamps and any resulting
        document. No response on this resource ever carries the link secret.
      x-permission: READ_SERVICING_DOCUMENT
      x-idempotent: false
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: invitationId
          in: path
          required: true
          description: Stable opaque invitation identifier.
          schema:
            type: string
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - invitationId
                  - invitationRef
                  - caseId
                  - evidenceType
                  - purposeCode
                  - state
                  - issuedAt
                  - expiresAt
                  - deliveredAt
                  - openedAt
                  - uploadedAt
                  - documentId
                  - localeCode
                properties:
                  invitationId:
                    type: integer
                  invitationRef:
                    type: string
                  caseId:
                    type: integer
                    description: Stable opaque servicing case identifier.
                  evidenceType:
                    type: string
                  purposeCode:
                    type: string
                  state:
                    type: string
                  issuedAt:
                    type: string
                    format: date-time
                  expiresAt:
                    type: string
                    format: date-time
                  deliveredAt:
                    type: string
                    format: date-time
                  openedAt:
                    type: string
                    format: date-time
                  uploadedAt:
                    type: string
                    format: date-time
                  documentId:
                    type: string
                  localeCode:
                    type: string
              example:
                invitationId: 6001
                invitationRef: LE-UPL-6001
                caseId: 1001
                evidenceType: MEDICAL_CERTIFICATE
                purposeCode: HARDSHIP_MEDICAL_LEAVE_EVIDENCE
                state: DELIVERED
                issuedAt: 2026-07-25T18:40:00Z
                expiresAt: 2026-08-01T18:40:00Z
                deliveredAt: 2026-07-25T18:41:00Z
                openedAt: null
                uploadedAt: null
                documentId: null
                localeCode: en
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
  /v1/servicing/document-invitations/{invitationId}/reissue:
    post:
      tags:
        - Case documents
      operationId: reissueDocumentInvitation
      summary: Reissue an invitation
      description: Supersedes the live invitation and issues a replacement with a fresh secret and deadline, so the borrower
        never holds two working links. The new invitation id is returned as resourceId.
      x-permission: ISSUE_SERVICING_DOCUMENT_INVITATION
      x-idempotent: true
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: invitationId
          in: path
          required: true
          description: Stable opaque invitation identifier.
          schema:
            type: string
        - name: Idempotency-Key
          in: header
          required: false
          description: Optional replay key for this logical mutation. Omission creates a fresh server-owned key for this attempt;
            blank, repeated, or longer-than-50-character values are rejected.
          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:
                      - invitationRef
                      - expiresAt
                      - secretDelivered
                    properties:
                      invitationRef:
                        type: string
                      expiresAt:
                        type: string
                        format: date-time
                      secretDelivered:
                        type: string
              example:
                resourceId: 6002
                changes:
                  invitationRef: LE-UPL-6002
                  expiresAt: 2026-08-08T18:40:00Z
                  secretDelivered: EMAIL
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
        "409":
          $ref: "#/components/responses/Servicing409Error"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - reason
              properties:
                reason:
                  type: string
              example:
                reason: The original link expired before the borrower could upload.
            example:
              reason: The original link expired before the borrower could upload.
  /v1/servicing/document-invitations/{invitationId}/revoke:
    post:
      tags:
        - Case documents
      operationId: revokeDocumentInvitation
      summary: Revoke an invitation
      description: Revokes a live invitation so the emailed link stops working immediately. Documents already uploaded through
        it are unaffected.
      x-permission: REVOKE_SERVICING_DOCUMENT_INVITATION
      x-idempotent: true
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: invitationId
          in: path
          required: true
          description: Stable opaque invitation identifier.
          schema:
            type: string
        - name: Idempotency-Key
          in: header
          required: false
          description: Optional replay key for this logical mutation. Omission creates a fresh server-owned key for this attempt;
            blank, repeated, or longer-than-50-character values are rejected.
          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:
                      - invitationId
                      - state
                    properties:
                      invitationId:
                        type: integer
                      state:
                        type: string
              example:
                resourceId: 6001
                changes:
                  invitationId: 6001
                  state: REVOKED
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
        "409":
          $ref: "#/components/responses/Servicing409Error"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - reason
              properties:
                reason:
                  type: string
              example:
                reason: Sent to the wrong contact point.
            example:
              reason: Sent to the wrong contact point.
  /v1/servicing/cookie/context:
    get:
      tags:
        - Cookie
      operationId: getCookieContext
      summary: Load the Cookie panel context
      description: "Returns everything the Cookie panel renders for one case: the case header, task and linked-loan bindings,
        server-declared capability states, suggestions, effective action levels, layered health, and the worker’s recent
        threads. Without caseId it returns the caseless navigation view with recent threads and health only."
      x-permission: REQUEST_SERVICING_COOKIE
      x-idempotent: false
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: caseId
          in: query
          required: false
          description: Case to bind the panel to; omitting it returns the caseless navigation view.
          schema:
            type: integer
        - name: taskId
          in: query
          required: false
          description: Task binding within the case.
          schema:
            type: integer
        - name: loanRef
          in: query
          required: false
          description: Explicitly selected loan for loan-specific question families.
          schema:
            type: string
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - caseBound
                  - caseId
                  - caseRef
                  - caseTypeCode
                  - caseTypeName
                  - caseStatus
                  - caseReasonCode
                  - customerRef
                  - sensitiveCase
                  - task
                  - linkedLoans
                  - selectedLoanRef
                  - loanSelectionRequired
                  - demoMode
                  - effectiveDataTime
                  - health
                  - capabilities
                  - suggestions
                  - actionLevels
                  - recentThreads
                properties:
                  caseBound:
                    type: boolean
                  caseId:
                    type: integer
                    description: Stable opaque servicing case identifier.
                  caseRef:
                    type: string
                  caseTypeCode:
                    type: string
                  caseTypeName:
                    type: string
                  caseStatus:
                    type: string
                  caseReasonCode:
                    type: string
                  customerRef:
                    type: string
                  sensitiveCase:
                    type: boolean
                  task:
                    type: object
                    required:
                      - taskId
                      - taskTypeCode
                      - status
                      - summary
                    properties:
                      taskId:
                        type: integer
                      taskTypeCode:
                        type: string
                      status:
                        type: string
                        description: Current normalized lifecycle state.
                      summary:
                        type: string
                  linkedLoans:
                    type: array
                    items:
                      type: object
                      required:
                        - loanRef
                        - label
                        - relationshipType
                        - status
                        - currency
                        - active
                        - suitabilityReason
                        - selected
                      properties:
                        loanRef:
                          type: string
                        label:
                          type: string
                        relationshipType:
                          type: string
                        status:
                          type: string
                          description: Current normalized lifecycle state.
                        currency:
                          type: string
                          pattern: ^[A-Z]{3}$
                          description: ISO 4217 currency code.
                        active:
                          type: boolean
                        suitabilityReason:
                          type: string
                        selected:
                          type: boolean
                  selectedLoanRef:
                    type: string
                  loanSelectionRequired:
                    type: boolean
                  demoMode:
                    type: boolean
                  effectiveDataTime:
                    type: string
                  health:
                    type: object
                    required:
                      - state
                      - directAnswersAvailable
                      - onlineSynthesisAvailable
                      - confirmedActionsAvailable
                      - configurationVersion
                      - demoMode
                      - suppressed
                      - circuitOpen
                    properties:
                      state:
                        type: string
                      directAnswersAvailable:
                        type: boolean
                      onlineSynthesisAvailable:
                        type: boolean
                      confirmedActionsAvailable:
                        type: boolean
                      configurationVersion:
                        type: integer
                      demoMode:
                        type: boolean
                      suppressed:
                        type: boolean
                      circuitOpen:
                        type: boolean
                  capabilities:
                    type: object
                    required:
                      - CASE_BRIEFING
                      - CURRENT_PAYOFF
                      - DRAFT_BORROWER_RESPONSE
                    properties:
                      CASE_BRIEFING:
                        type: object
                        required:
                          - state
                          - path
                          - loanSpecific
                        properties:
                          state:
                            type: string
                          path:
                            type: string
                          loanSpecific:
                            type: boolean
                      CURRENT_PAYOFF:
                        type: object
                        required:
                          - state
                          - path
                          - loanSpecific
                        properties:
                          state:
                            type: string
                          path:
                            type: string
                          loanSpecific:
                            type: boolean
                      DRAFT_BORROWER_RESPONSE:
                        type: object
                        required:
                          - state
                          - path
                          - loanSpecific
                        properties:
                          state:
                            type: string
                          path:
                            type: string
                          loanSpecific:
                            type: boolean
                  suggestions:
                    type: array
                    items:
                      type: object
                      required:
                        - code
                        - text
                        - path
                        - capabilityState
                      properties:
                        code:
                          type: string
                        text:
                          type: string
                        path:
                          type: string
                        capabilityState:
                          type: string
                  actionLevels:
                    type: object
                    required:
                      - DRAFT_CASE_NOTE
                      - SAVE_CASE_NOTE
                      - PREPARE_FOLLOW_UP_TASK
                      - PREPARE_PAYMENT_ARRANGEMENT
                    properties:
                      DRAFT_CASE_NOTE:
                        type: string
                      SAVE_CASE_NOTE:
                        type: string
                      PREPARE_FOLLOW_UP_TASK:
                        type: string
                      PREPARE_PAYMENT_ARRANGEMENT:
                        type: string
                  recentThreads:
                    type: array
                    items:
                      type: object
                      required:
                        - threadId
                        - caseId
                        - caseRef
                        - caseStatus
                        - caseTypeCode
                        - caseTypeName
                        - status
                        - turnCount
                        - lastTurnAt
                      properties:
                        threadId:
                          type: integer
                        caseId:
                          type: integer
                          description: Stable opaque servicing case identifier.
                        caseRef:
                          type: string
                        caseStatus:
                          type: string
                        caseTypeCode:
                          type: string
                        caseTypeName:
                          type: string
                        status:
                          type: string
                          description: Current normalized lifecycle state.
                        turnCount:
                          type: integer
                        lastTurnAt:
                          type: string
                          format: date-time
              example:
                caseBound: true
                caseId: 1001
                caseRef: LE-CASE-1001
                caseTypeCode: COLLECTIONS
                caseTypeName: Collections
                caseStatus: OPEN
                caseReasonCode: PAYMENT_FAILURE
                customerRef: "123"
                sensitiveCase: false
                task:
                  taskId: 2001
                  taskTypeCode: COLLECTIONS_OUTREACH
                  status: IN_PROGRESS
                  summary: Call the customer about the missed payment.
                linkedLoans:
                  - loanRef: "456"
                    label: Personal loan 456
                    relationshipType: BORROWER
                    status: ACTIVE
                    currency: USD
                    active: true
                    suitabilityReason: CASE_LINKED
                    selected: true
                selectedLoanRef: "456"
                loanSelectionRequired: false
                demoMode: false
                effectiveDataTime: 2026-07-25T18:40:00Z
                health:
                  state: HEALTHY
                  directAnswersAvailable: true
                  onlineSynthesisAvailable: true
                  confirmedActionsAvailable: true
                  configurationVersion: 4
                  demoMode: false
                  suppressed: false
                  circuitOpen: false
                capabilities:
                  CASE_BRIEFING:
                    state: AVAILABLE
                    path: SYNTHESIZED
                    loanSpecific: false
                  CURRENT_PAYOFF:
                    state: AVAILABLE
                    path: DIRECT
                    loanSpecific: true
                  DRAFT_BORROWER_RESPONSE:
                    state: PREVIEW_ONLY
                    path: SYNTHESIZED
                    loanSpecific: false
                suggestions:
                  - code: CASE_BRIEFING
                    text: Brief me on this case
                    path: SYNTHESIZED
                    capabilityState: AVAILABLE
                actionLevels:
                  DRAFT_CASE_NOTE: DRAFT
                  SAVE_CASE_NOTE: CONFIRM_AND_SUBMIT
                  PREPARE_FOLLOW_UP_TASK: PREPARE
                  PREPARE_PAYMENT_ARRANGEMENT: PREVIEW_ONLY
                recentThreads:
                  - threadId: 8101
                    caseId: 1001
                    caseRef: LE-CASE-1001
                    caseStatus: OPEN
                    caseTypeCode: COLLECTIONS
                    caseTypeName: Collections
                    status: ACTIVE
                    turnCount: 3
                    lastTurnAt: 2026-07-25T18:40:00Z
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
  /v1/servicing/cookie/threads:
    get:
      tags:
        - Cookie
      operationId: listCookieThreads
      summary: List recent Cookie threads
      description: Lists the authenticated worker’s recent case-scoped Cookie threads, newest activity first. Threads are per
        case and per human worker.
      x-permission: REQUEST_SERVICING_COOKIE
      x-idempotent: false
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: limit
          in: query
          required: false
          description: Maximum threads to return.
          schema:
            type: integer
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - threads
                properties:
                  threads:
                    type: array
                    items:
                      type: object
                      required:
                        - threadId
                        - caseId
                        - caseRef
                        - caseStatus
                        - caseTypeCode
                        - caseTypeName
                        - status
                        - turnCount
                        - lastTurnAt
                      properties:
                        threadId:
                          type: integer
                        caseId:
                          type: integer
                          description: Stable opaque servicing case identifier.
                        caseRef:
                          type: string
                        caseStatus:
                          type: string
                        caseTypeCode:
                          type: string
                        caseTypeName:
                          type: string
                        status:
                          type: string
                          description: Current normalized lifecycle state.
                        turnCount:
                          type: integer
                        lastTurnAt:
                          type: string
                          format: date-time
              example:
                threads:
                  - threadId: 8101
                    caseId: 1001
                    caseRef: LE-CASE-1001
                    caseStatus: OPEN
                    caseTypeCode: COLLECTIONS
                    caseTypeName: Collections
                    status: ACTIVE
                    turnCount: 3
                    lastTurnAt: 2026-07-25T18:40:00Z
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
  /v1/servicing/cookie/threads/{threadId}/turns:
    get:
      tags:
        - Cookie
      operationId: listCookieThreadTurns
      summary: List the turns in a Cookie thread
      description: Returns every turn in one thread as terminal metadata plus the accepted answer body where one exists.
        Answer statuses are GROUNDED, PARTIAL, UNAVAILABLE, DECLINED, BLOCKED, or FAILED.
      x-permission: REQUEST_SERVICING_COOKIE
      x-idempotent: false
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: threadId
          in: path
          required: true
          description: Stable opaque thread identifier.
          schema:
            type: string
        - name: limit
          in: query
          required: false
          description: Maximum turns to return.
          schema:
            type: integer
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - turns
                properties:
                  turns:
                    type: array
                    items:
                      type: object
                      required:
                        - turnId
                        - seq
                        - questionFamily
                        - answerPath
                        - answerStatus
                        - terminalAt
                        - answer
                      properties:
                        turnId:
                          type: integer
                        seq:
                          type: integer
                        questionFamily:
                          type: string
                        answerPath:
                          type: string
                        answerStatus:
                          type: string
                        terminalAt:
                          type: string
                          format: date-time
                        answer:
                          type: object
                          required:
                            - answerStatus
                            - answerKind
                            - answer
                            - assertions
                            - citations
                            - missingFacts
                            - warnings
                            - attentionItems
                            - proposedActions
                          properties:
                            answerStatus:
                              type: string
                            answerKind:
                              type: string
                            answer:
                              type: string
                            assertions:
                              type: array
                              items:
                                type: object
                                required:
                                  - claimType
                                  - text
                                  - value
                                  - derivation
                                  - sourceRefs
                                properties:
                                  claimType:
                                    type: string
                                  text:
                                    type: string
                                  value:
                                    type: string
                                  derivation:
                                    type: string
                                  sourceRefs:
                                    type: array
                                    items:
                                      type: string
                            citations:
                              type: array
                              items:
                                type: object
                                required:
                                  - type
                                  - publicRef
                                  - label
                                  - sourceTime
                                  - freshness
                                  - deepLink
                                properties:
                                  type:
                                    type: string
                                  publicRef:
                                    type: string
                                  label:
                                    type: string
                                  sourceTime:
                                    type: string
                                  freshness:
                                    type: string
                                  deepLink:
                                    type: string
                            missingFacts:
                              type: array
                              items:
                                type: object
                            warnings:
                              type: array
                              items:
                                type: object
                            attentionItems:
                              type: array
                              items:
                                type: object
                            proposedActions:
                              type: array
                              items:
                                type: object
              example:
                turns:
                  - turnId: 8201
                    seq: 1
                    questionFamily: CURRENT_PAYOFF
                    answerPath: DIRECT
                    answerStatus: GROUNDED
                    terminalAt: 2026-07-25T18:40:00Z
                    answer:
                      answerStatus: GROUNDED
                      answerKind: VERIFIED_FACT
                      answer: The payoff for loan 456 today is 1,254.10 USD.
                      assertions:
                        - claimType: PAYOFF_TOTAL
                          text: Payoff total as of today
                          value: 1254.10 USD
                          derivation: SOURCED
                          sourceRefs:
                            - loan:456
                      citations:
                        - type: LOAN
                          publicRef: loan:456
                          label: Loan 456 servicing record
                          sourceTime: 2026-07-25T18:40:00Z
                          freshness: CURRENT
                          deepLink: /loans/456
                      missingFacts: []
                      warnings: []
                      attentionItems: []
                      proposedActions: []
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
  /v1/servicing/cookie/threads/close:
    post:
      tags:
        - Cookie
      operationId: closeCookieThread
      summary: Close the open Cookie thread
      description: Closes the worker’s open thread on a case so the next question starts a new conversation. Audit-bearing
        sessions and outputs are untouched.
      x-permission: REQUEST_SERVICING_COOKIE
      x-idempotent: true
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: Idempotency-Key
          in: header
          required: false
          description: Optional replay key for this logical mutation. Omission creates a fresh server-owned key for this attempt;
            blank, repeated, or longer-than-50-character values are rejected.
          schema:
            type: string
            minLength: 1
            maxLength: 50
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - closed
                properties:
                  closed:
                    type: boolean
              example:
                closed: true
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
        "409":
          $ref: "#/components/responses/Servicing409Error"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - caseId
              properties:
                caseId:
                  type: integer
                  description: Stable opaque servicing case identifier.
              example:
                caseId: 1001
            example:
              caseId: 1001
  /v1/servicing/cases/{caseId}/cookie/turns:
    post:
      tags:
        - Cookie
      operationId: createCookieTurn
      summary: Ask Cookie a case-scoped question
      description: "Runs one Cookie turn through the governed command pipeline: the question classifies into a closed family,
        direct families answer from deterministic reads, and synthesized families call the online worker under packet
        and schema validation. Exactly one of question or suggestionCode is supplied, and a replayed idempotencyKey
        returns the originally accepted answer."
      x-permission: REQUEST_SERVICING_COOKIE
      x-idempotent: true
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: caseId
          in: path
          required: true
          description: Positive numeric case identifier.
          schema:
            type: integer
            format: int64
            minimum: 1
        - name: Idempotency-Key
          in: header
          required: false
          description: Optional replay key for this logical mutation. Omission creates a fresh server-owned key for this attempt;
            blank, repeated, or longer-than-50-character values are rejected.
          schema:
            type: string
            minLength: 1
            maxLength: 50
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - turnId
                  - replayed
                  - threadId
                  - answer
                properties:
                  turnId:
                    type: integer
                  replayed:
                    type: boolean
                  threadId:
                    type: integer
                  answer:
                    type: object
                    required:
                      - answerStatus
                      - answerKind
                      - answer
                      - assertions
                      - citations
                      - missingFacts
                      - warnings
                      - attentionItems
                      - proposedActions
                      - runtime
                    properties:
                      answerStatus:
                        type: string
                      answerKind:
                        type: string
                      answer:
                        type: string
                      assertions:
                        type: array
                        items:
                          type: object
                          required:
                            - claimType
                            - text
                            - value
                            - derivation
                            - sourceRefs
                          properties:
                            claimType:
                              type: string
                            text:
                              type: string
                            value:
                              type: string
                            derivation:
                              type: string
                            sourceRefs:
                              type: array
                              items:
                                type: string
                      citations:
                        type: array
                        items:
                          type: object
                          required:
                            - type
                            - publicRef
                            - label
                            - sourceTime
                            - freshness
                            - deepLink
                          properties:
                            type:
                              type: string
                            publicRef:
                              type: string
                            label:
                              type: string
                            sourceTime:
                              type: string
                            freshness:
                              type: string
                            deepLink:
                              type: string
                      missingFacts:
                        type: array
                        items:
                          type: object
                      warnings:
                        type: array
                        items:
                          type: object
                      attentionItems:
                        type: array
                        items:
                          type: object
                      proposedActions:
                        type: array
                        items:
                          type: object
                      runtime:
                        type: object
                        required:
                          - turnId
                          - answerPath
                          - correlationRef
                          - policyVersion
                          - schemaVersion
                        properties:
                          turnId:
                            type: integer
                          answerPath:
                            type: string
                          correlationRef:
                            type: string
                          policyVersion:
                            type: string
                          schemaVersion:
                            type: string
              example:
                turnId: 8201
                replayed: false
                threadId: 8101
                answer:
                  answerStatus: GROUNDED
                  answerKind: VERIFIED_FACT
                  answer: The payoff for loan 456 today is 1,254.10 USD.
                  assertions:
                    - claimType: PAYOFF_TOTAL
                      text: Payoff total as of today
                      value: 1254.10 USD
                      derivation: SOURCED
                      sourceRefs:
                        - loan:456
                  citations:
                    - type: LOAN
                      publicRef: loan:456
                      label: Loan 456 servicing record
                      sourceTime: 2026-07-25T18:40:00Z
                      freshness: CURRENT
                      deepLink: /loans/456
                  missingFacts: []
                  warnings: []
                  attentionItems: []
                  proposedActions: []
                  runtime:
                    turnId: 8201
                    answerPath: DIRECT
                    correlationRef: ck-7f3a2c
                    policyVersion: "4"
                    schemaVersion: cookie-answer-v1
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
        "409":
          $ref: "#/components/responses/Servicing409Error"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - idempotencyKey
              properties:
                question:
                  type: string
                taskId:
                  type: integer
                loanRef:
                  type: string
                idempotencyKey:
                  type: string
                goodThroughDate:
                  type: string
                  format: date
              example:
                question: What is the payoff today?
                taskId: 2001
                loanRef: "456"
                idempotencyKey: cookie-turn-2026-07-25-0001
                goodThroughDate: 2026-07-31
            example:
              question: What is the payoff today?
              taskId: 2001
              loanRef: "456"
              idempotencyKey: cookie-turn-2026-07-25-0001
              goodThroughDate: 2026-07-31
  /v1/servicing/cookie/turns/{turnId}:
    get:
      tags:
        - Cookie
      operationId: getCookieTurn
      summary: Retrieve a Cookie turn
      description: Returns one turn’s terminal result and accepted answer for polling or reopening a thread. Resolving the
        turn re-checks case visibility, so a turn reference is never a way around the case read boundary.
      x-permission: REQUEST_SERVICING_COOKIE
      x-idempotent: false
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: turnId
          in: path
          required: true
          description: Stable opaque turn identifier.
          schema:
            type: string
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - turnId
                  - threadId
                  - questionFamily
                  - answerPath
                  - answerStatus
                  - terminalAt
                  - correlationRef
                  - answer
                properties:
                  turnId:
                    type: integer
                  threadId:
                    type: integer
                  questionFamily:
                    type: string
                  answerPath:
                    type: string
                  answerStatus:
                    type: string
                  terminalAt:
                    type: string
                    format: date-time
                  correlationRef:
                    type: string
                  answer:
                    type: object
                    required:
                      - answerStatus
                      - answerKind
                      - answer
                      - assertions
                      - citations
                      - missingFacts
                      - warnings
                      - attentionItems
                      - proposedActions
                    properties:
                      answerStatus:
                        type: string
                      answerKind:
                        type: string
                      answer:
                        type: string
                      assertions:
                        type: array
                        items:
                          type: object
                          required:
                            - claimType
                            - text
                            - value
                            - derivation
                            - sourceRefs
                          properties:
                            claimType:
                              type: string
                            text:
                              type: string
                            value:
                              type: string
                            derivation:
                              type: string
                            sourceRefs:
                              type: array
                              items:
                                type: string
                      citations:
                        type: array
                        items:
                          type: object
                          required:
                            - type
                            - publicRef
                            - label
                            - sourceTime
                            - freshness
                            - deepLink
                          properties:
                            type:
                              type: string
                            publicRef:
                              type: string
                            label:
                              type: string
                            sourceTime:
                              type: string
                            freshness:
                              type: string
                            deepLink:
                              type: string
                      missingFacts:
                        type: array
                        items:
                          type: object
                      warnings:
                        type: array
                        items:
                          type: object
                      attentionItems:
                        type: array
                        items:
                          type: object
                      proposedActions:
                        type: array
                        items:
                          type: object
              example:
                turnId: 8201
                threadId: 8101
                questionFamily: CURRENT_PAYOFF
                answerPath: DIRECT
                answerStatus: GROUNDED
                terminalAt: 2026-07-25T18:40:00Z
                correlationRef: ck-7f3a2c
                answer:
                  answerStatus: GROUNDED
                  answerKind: VERIFIED_FACT
                  answer: The payoff for loan 456 today is 1,254.10 USD.
                  assertions:
                    - claimType: PAYOFF_TOTAL
                      text: Payoff total as of today
                      value: 1254.10 USD
                      derivation: SOURCED
                      sourceRefs:
                        - loan:456
                  citations:
                    - type: LOAN
                      publicRef: loan:456
                      label: Loan 456 servicing record
                      sourceTime: 2026-07-25T18:40:00Z
                      freshness: CURRENT
                      deepLink: /loans/456
                  missingFacts: []
                  warnings: []
                  attentionItems: []
                  proposedActions: []
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
  /v1/servicing/cookie/turns/{turnId}/feedback:
    post:
      tags:
        - Cookie
      operationId: submitCookieTurnFeedback
      summary: Record feedback on a Cookie answer
      description: Records one worker’s feedback on an accepted answer using the closed category set HELPFUL, INCORRECT,
        INCOMPLETE, UNSAFE, or SOURCE_PROBLEM. A repeat submission by the same worker updates the earlier entry.
      x-permission: REQUEST_SERVICING_COOKIE
      x-idempotent: true
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: turnId
          in: path
          required: true
          description: Stable opaque turn identifier.
          schema:
            type: string
        - name: Idempotency-Key
          in: header
          required: false
          description: Optional replay key for this logical mutation. Omission creates a fresh server-owned key for this attempt;
            blank, repeated, or longer-than-50-character values are rejected.
          schema:
            type: string
            minLength: 1
            maxLength: 50
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - feedbackId
                properties:
                  feedbackId:
                    type: integer
              example:
                feedbackId: 8401
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
        "409":
          $ref: "#/components/responses/Servicing409Error"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - category
              properties:
                category:
                  type: string
                comment:
                  type: string
              example:
                category: HELPFUL
                comment: Matched the ledger exactly.
            example:
              category: HELPFUL
              comment: Matched the ledger exactly.
  /v1/servicing/cookie/proposals/{proposalId}/confirm:
    post:
      tags:
        - Cookie
      operationId: confirmCookieProposal
      summary: Confirm a Cookie proposal
      description: Submits a prepared action through its owning command, so authorization comes from the owning permission
        (note creation, follow-up task creation, or task reassignment), never from the Cookie request permission.
        Outcomes are SUBMITTED, STALE_PREVIEW, EXPIRED, BLOCKED, or FAILED, and attestation fields such as a
        reassignment reason must come from the human.
      x-permission: CREATE_SERVICING_NOTE
      x-idempotent: true
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: proposalId
          in: path
          required: true
          description: Stable opaque proposal identifier.
          schema:
            type: string
        - name: Idempotency-Key
          in: header
          required: false
          description: Optional replay key for this logical mutation. Omission creates a fresh server-owned key for this attempt;
            blank, repeated, or longer-than-50-character values are rejected.
          schema:
            type: string
            minLength: 1
            maxLength: 50
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - outcome
                  - message
                  - correlationRef
                  - resourceId
                  - resourceType
                  - deepLink
                properties:
                  outcome:
                    type: string
                  message:
                    type: string
                  correlationRef:
                    type: string
                  resourceId:
                    type: integer
                  resourceType:
                    type: string
                  deepLink:
                    type: string
              example:
                outcome: SUBMITTED
                message: The note was saved to the case.
                correlationRef: ck-7f3a2c
                resourceId: 4501
                resourceType: NOTE
                deepLink: /servicing/cases/1001/notes/4501
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
        "409":
          $ref: "#/components/responses/Servicing409Error"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - confirmationIdempotencyKey
                - attestation
              properties:
                confirmationIdempotencyKey:
                  type: string
                attestation:
                  type: object
                  required:
                    - body
                  properties:
                    body:
                      type: string
              example:
                confirmationIdempotencyKey: cookie-confirm-8301-1
                attestation:
                  body: Customer promised to pay on 2026-08-01.
            example:
              confirmationIdempotencyKey: cookie-confirm-8301-1
              attestation:
                body: Customer promised to pay on 2026-08-01.
  /v1/servicing/cookie/admin/config:
    get:
      tags:
        - Cookie
      operationId: getCookieAdminConfig
      summary: Read the Cookie configuration
      description: "Returns the active policy under the cookie-config-v1 contract, its version history, and the code-declared
        surface: question families, the action catalog, source groups, and exclusion reasons. Provider endpoints, model
        identifiers, prompts, and credentials are never reported."
      x-permission: ADMIN_SERVICING_AI
      x-idempotent: false
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - version
                  - demoOnly
                  - policyContract
                  - policy
                  - versions
                  - declared
                properties:
                  version:
                    type: integer
                    description: Monotonically increasing resource version.
                  demoOnly:
                    type: boolean
                  policyContract:
                    type: string
                  policy:
                    type: object
                    required:
                      - activation
                      - workerBinding
                      - capabilities
                      - suggestionOrder
                      - data
                      - actions
                      - runtimeLimits
                      - quality
                    properties:
                      activation:
                        type: object
                        required:
                          - enabled
                          - demoMode
                          - allowedCaseTypes
                        properties:
                          enabled:
                            type: boolean
                          demoMode:
                            type: boolean
                          allowedCaseTypes:
                            type: array
                            items:
                              type: string
                      workerBinding:
                        type: object
                        required:
                          - workerCode
                          - adapterContract
                        properties:
                          workerCode:
                            type: string
                          adapterContract:
                            type: string
                      capabilities:
                        type: object
                        required:
                          - CASE_BRIEFING
                          - CURRENT_PAYOFF
                          - DRAFT_BORROWER_RESPONSE
                        properties:
                          CASE_BRIEFING:
                            type: string
                          CURRENT_PAYOFF:
                            type: string
                          DRAFT_BORROWER_RESPONSE:
                            type: string
                      suggestionOrder:
                        type: array
                        items:
                          type: string
                      data:
                        type: object
                        required:
                          - permittedSourceGroups
                          - sourceRecencyDays
                          - maxRecordsPerGroup
                          - maxExcerptCharacters
                          - maxConversationTurns
                          - maxPacketBytes
                          - includeSensitiveSources
                        properties:
                          permittedSourceGroups:
                            type: array
                            items:
                              type: string
                          sourceRecencyDays:
                            type: integer
                          maxRecordsPerGroup:
                            type: integer
                          maxExcerptCharacters:
                            type: integer
                          maxConversationTurns:
                            type: integer
                          maxPacketBytes:
                            type: integer
                          includeSensitiveSources:
                            type: boolean
                      actions:
                        type: object
                        required:
                          - capabilityModes
                          - confirmedActionsEnabled
                        properties:
                          capabilityModes:
                            type: object
                            required:
                              - SAVE_CASE_NOTE
                              - PREPARE_PAYMENT_ARRANGEMENT
                            properties:
                              SAVE_CASE_NOTE:
                                type: string
                              PREPARE_PAYMENT_ARRANGEMENT:
                                type: string
                          confirmedActionsEnabled:
                            type: boolean
                      runtimeLimits:
                        type: object
                        required:
                          - activeTurnsPerUserCase
                          - caseTurnsPerTenMinutes
                          - userTurnsPerHour
                          - tenantTurnsPerDay
                          - tenantConcurrentTurns
                          - providerTimeoutSeconds
                          - maxQuestionCharacters
                          - maxOutputTokens
                          - circuitFailureThreshold
                          - proposalExpiryMinutes
                        properties:
                          activeTurnsPerUserCase:
                            type: integer
                          caseTurnsPerTenMinutes:
                            type: integer
                          userTurnsPerHour:
                            type: integer
                          tenantTurnsPerDay:
                            type: integer
                          tenantConcurrentTurns:
                            type: integer
                          providerTimeoutSeconds:
                            type: integer
                          maxQuestionCharacters:
                            type: integer
                          maxOutputTokens:
                            type: integer
                          circuitFailureThreshold:
                            type: integer
                          proposalExpiryMinutes:
                            type: integer
                      quality:
                        type: object
                        required:
                          - minimumRuntimeRelease
                          - evaluationSetVersion
                          - thresholdProfile
                          - sampleReviewRate
                          - feedbackEnabled
                        properties:
                          minimumRuntimeRelease:
                            type: string
                          evaluationSetVersion:
                            type: string
                          thresholdProfile:
                            type: string
                          sampleReviewRate:
                            type: number
                          feedbackEnabled:
                            type: boolean
                  versions:
                    type: array
                    items:
                      type: object
                      required:
                        - version
                        - status
                        - demoOnly
                        - reason
                        - createdAt
                        - activatedAt
                      properties:
                        version:
                          type: integer
                          description: Monotonically increasing resource version.
                        status:
                          type: string
                          description: Current normalized lifecycle state.
                        demoOnly:
                          type: boolean
                        reason:
                          type: string
                        createdAt:
                          type: string
                          format: date-time
                        activatedAt:
                          type: string
                          format: date-time
                  declared:
                    type: object
                    required:
                      - questionFamilies
                      - actionCatalog
                      - sourceGroups
                      - exclusionReasons
                    properties:
                      questionFamilies:
                        type: array
                        items:
                          type: object
                          required:
                            - code
                            - path
                            - loanSpecific
                            - state
                            - permittedSourceGroups
                          properties:
                            code:
                              type: string
                            path:
                              type: string
                            loanSpecific:
                              type: boolean
                            state:
                              type: string
                            permittedSourceGroups:
                              type: array
                              items:
                                type: string
                      actionCatalog:
                        type: array
                        items:
                          type: object
                          required:
                            - capabilityCode
                            - maximumLevel
                            - configuredMode
                            - effectiveLevel
                            - owningCommand
                            - permission
                            - verb
                            - description
                          properties:
                            capabilityCode:
                              type: string
                            maximumLevel:
                              type: string
                            configuredMode:
                              type: string
                            effectiveLevel:
                              type: string
                            owningCommand:
                              type: string
                            permission:
                              type: string
                            verb:
                              type: string
                            description:
                              type: string
                      sourceGroups:
                        type: array
                        items:
                          type: string
                      exclusionReasons:
                        type: array
                        items:
                          type: string
              example:
                version: 4
                demoOnly: false
                policyContract: cookie-config-v1
                policy:
                  activation:
                    enabled: true
                    demoMode: false
                    allowedCaseTypes:
                      - COLLECTIONS
                  workerBinding:
                    workerCode: COOKIE
                    adapterContract: cookie-adapter-v1
                  capabilities:
                    CASE_BRIEFING: AVAILABLE
                    CURRENT_PAYOFF: AVAILABLE
                    DRAFT_BORROWER_RESPONSE: PREVIEW_ONLY
                  suggestionOrder:
                    - CASE_BRIEFING
                    - CURRENT_PAYOFF
                  data:
                    permittedSourceGroups:
                      - CASE
                      - TASK
                      - NOTE
                      - LOAN
                      - PAYMENT
                    sourceRecencyDays: 365
                    maxRecordsPerGroup: 25
                    maxExcerptCharacters: 1200
                    maxConversationTurns: 12
                    maxPacketBytes: 262144
                    includeSensitiveSources: false
                  actions:
                    capabilityModes:
                      SAVE_CASE_NOTE: CONFIRM_AND_SUBMIT
                      PREPARE_PAYMENT_ARRANGEMENT: PREVIEW_ONLY
                    confirmedActionsEnabled: true
                  runtimeLimits:
                    activeTurnsPerUserCase: 1
                    caseTurnsPerTenMinutes: 20
                    userTurnsPerHour: 60
                    tenantTurnsPerDay: 2000
                    tenantConcurrentTurns: 8
                    providerTimeoutSeconds: 30
                    maxQuestionCharacters: 500
                    maxOutputTokens: 2048
                    circuitFailureThreshold: 5
                    proposalExpiryMinutes: 30
                  quality:
                    minimumRuntimeRelease: 2026.07.1
                    evaluationSetVersion: cookie-eval-2026-06
                    thresholdProfile: STANDARD
                    sampleReviewRate: 0.05
                    feedbackEnabled: true
                versions:
                  - version: 4
                    status: ACTIVE
                    demoOnly: false
                    reason: Enable confirmed actions for collections.
                    createdAt: 2026-07-20T09:00:00Z
                    activatedAt: 2026-07-20T09:00:00Z
                declared:
                  questionFamilies:
                    - code: CURRENT_PAYOFF
                      path: DIRECT
                      loanSpecific: true
                      state: AVAILABLE
                      permittedSourceGroups:
                        - LOAN
                        - PAYMENT
                  actionCatalog:
                    - capabilityCode: SAVE_CASE_NOTE
                      maximumLevel: CONFIRM_AND_SUBMIT
                      configuredMode: CONFIRM_AND_SUBMIT
                      effectiveLevel: CONFIRM_AND_SUBMIT
                      owningCommand: CREATE SERVICING_NOTE
                      permission: CREATE_SERVICING_NOTE
                      verb: Save note
                      description: Save the reviewed content as an ordinary case note.
                  sourceGroups:
                    - CASE
                    - CUSTOMER
                    - DECISION
                    - DOCUMENT
                    - EVENT
                    - INTERACTION
                    - LOAN
                    - NOTE
                    - PAYMENT
                    - PROMISE
                    - RESTRICTION
                    - TASK
                    - WORKFLOW
                  exclusionReasons:
                    - LIMIT_REACHED
                    - NOT_PERMITTED
                    - NOT_REQUESTED
                    - SENSITIVE_EXCLUDED
                    - STALE
                    - UNAVAILABLE
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
    put:
      tags:
        - Cookie
      operationId: updateCookieAdminConfig
      summary: Activate a Cookie policy version
      description: Activates a new policy version through the AI administration command with actor, reason, and audit.
        expectedVersion is required so a stale change is a conflict rather than an overwrite.
      x-permission: ADMIN_SERVICING_AI
      x-idempotent: true
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: Idempotency-Key
          in: header
          required: false
          description: Optional replay key for this logical mutation. Omission creates a fresh server-owned key for this attempt;
            blank, repeated, or longer-than-50-character values are rejected.
          schema:
            type: string
            minLength: 1
            maxLength: 50
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - version
                  - changes
                properties:
                  version:
                    type: integer
                    description: Monotonically increasing resource version.
                  changes:
                    type: object
                    required:
                      - cookieConfigVersion
                    properties:
                      cookieConfigVersion:
                        type: integer
              example:
                version: 5
                changes:
                  cookieConfigVersion: 5
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
        "409":
          $ref: "#/components/responses/Servicing409Error"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - policy
                - reason
                - expectedVersion
              properties:
                policy:
                  type: object
                  required:
                    - activation
                    - actions
                  properties:
                    activation:
                      type: object
                      required:
                        - enabled
                        - demoMode
                        - allowedCaseTypes
                      properties:
                        enabled:
                          type: boolean
                        demoMode:
                          type: boolean
                        allowedCaseTypes:
                          type: array
                          items:
                            type: string
                    actions:
                      type: object
                      required:
                        - capabilityModes
                        - confirmedActionsEnabled
                      properties:
                        capabilityModes:
                          type: object
                          required:
                            - SAVE_CASE_NOTE
                          properties:
                            SAVE_CASE_NOTE:
                              type: string
                        confirmedActionsEnabled:
                          type: boolean
                demoOnly:
                  type: boolean
                reason:
                  type: string
                expectedVersion:
                  type: integer
              example:
                policy:
                  activation:
                    enabled: true
                    demoMode: false
                    allowedCaseTypes:
                      - COLLECTIONS
                  actions:
                    capabilityModes:
                      SAVE_CASE_NOTE: CONFIRM_AND_SUBMIT
                    confirmedActionsEnabled: true
                demoOnly: false
                reason: Enable confirmed note saves for collections.
                expectedVersion: 4
            example:
              policy:
                activation:
                  enabled: true
                  demoMode: false
                  allowedCaseTypes:
                    - COLLECTIONS
                actions:
                  capabilityModes:
                    SAVE_CASE_NOTE: CONFIRM_AND_SUBMIT
                  confirmedActionsEnabled: true
              demoOnly: false
              reason: Enable confirmed note saves for collections.
              expectedVersion: 4
  /v1/servicing/cookie/admin/health:
    get:
      tags:
        - Cookie
      operationId: getCookieAdminHealth
      summary: Read Cookie health
      description: Returns derived per-layer health computed from configuration, worker registration, suppression, circuit
        state, and the recent turn record. The overall state is HEALTHY, ACTIONS_DISABLED, DIRECT_ONLY, DEGRADED,
        SUPPRESSED, or DISABLED.
      x-permission: ADMIN_SERVICING_AI
      x-idempotent: false
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - state
                  - directAnswersAvailable
                  - onlineSynthesisAvailable
                  - confirmedActionsAvailable
                  - configurationVersion
                  - demoMode
                  - demoOnlyConfiguration
                  - productionEnvironment
                  - workerCode
                  - adapterContract
                  - workerRegistered
                  - suppressed
                  - circuitOpen
                  - consecutiveWorkerFailures
                  - last24Hours
                properties:
                  state:
                    type: string
                  directAnswersAvailable:
                    type: boolean
                  onlineSynthesisAvailable:
                    type: boolean
                  confirmedActionsAvailable:
                    type: boolean
                  configurationVersion:
                    type: integer
                  demoMode:
                    type: boolean
                  demoOnlyConfiguration:
                    type: boolean
                  productionEnvironment:
                    type: boolean
                  workerCode:
                    type: string
                  adapterContract:
                    type: string
                  workerRegistered:
                    type: boolean
                  suppressed:
                    type: boolean
                  circuitOpen:
                    type: boolean
                  consecutiveWorkerFailures:
                    type: integer
                  last24Hours:
                    type: object
                    required:
                      - directTurns
                      - onlineTurns
                      - accepted
                      - rejected
                    properties:
                      directTurns:
                        type: integer
                      onlineTurns:
                        type: integer
                      accepted:
                        type: integer
                      rejected:
                        type: integer
              example:
                state: HEALTHY
                directAnswersAvailable: true
                onlineSynthesisAvailable: true
                confirmedActionsAvailable: true
                configurationVersion: 4
                demoMode: false
                demoOnlyConfiguration: false
                productionEnvironment: true
                workerCode: COOKIE
                adapterContract: cookie-adapter-v1
                workerRegistered: true
                suppressed: false
                circuitOpen: false
                consecutiveWorkerFailures: 0
                last24Hours:
                  directTurns: 42
                  onlineTurns: 17
                  accepted: 55
                  rejected: 1
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
  /v1/servicing/cookie/admin/usage:
    get:
      tags:
        - Cookie
      operationId: getCookieAdminUsage
      summary: Read Cookie usage aggregates
      description: "Returns usage and quality aggregates with no question or answer bodies: daily counts, family and status
        breakdowns, usage buckets, action outcomes, feedback, and current quota windows. Stratified cells below the
        minimum count report turns as -1 with suppressed true."
      x-permission: ADMIN_SERVICING_AI
      x-idempotent: false
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: days
          in: query
          required: false
          description: Aggregation window in days.
          schema:
            type: integer
            minimum: 1
            maximum: 90
            default: 7
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - windowDays
                  - daily
                  - byFamily
                  - usageBuckets
                  - actionOutcomes
                  - feedback
                  - quotaWindows
                properties:
                  windowDays:
                    type: integer
                  daily:
                    type: array
                    items:
                      type: object
                      required:
                        - day
                        - directTurns
                        - onlineTurns
                        - declinedTurns
                        - quotaRefused
                        - providerFailures
                        - acceptedAnswers
                        - averageLatencyMs
                      properties:
                        day:
                          type: string
                        directTurns:
                          type: integer
                        onlineTurns:
                          type: integer
                        declinedTurns:
                          type: integer
                        quotaRefused:
                          type: integer
                        providerFailures:
                          type: integer
                        acceptedAnswers:
                          type: integer
                        averageLatencyMs:
                          type: integer
                  byFamily:
                    type: array
                    items:
                      type: object
                      required:
                        - questionFamily
                        - answerPath
                        - answerStatus
                        - turns
                        - suppressed
                      properties:
                        questionFamily:
                          type: string
                        answerPath:
                          type: string
                        answerStatus:
                          type: string
                        turns:
                          type: integer
                        suppressed:
                          type: boolean
                  usageBuckets:
                    type: array
                    items:
                      type: object
                      required:
                        - bucket
                        - turns
                      properties:
                        bucket:
                          type: string
                        turns:
                          type: integer
                  actionOutcomes:
                    type: array
                    items:
                      type: object
                      required:
                        - capabilityCode
                        - status
                        - proposals
                      properties:
                        capabilityCode:
                          type: string
                        status:
                          type: string
                          description: Current normalized lifecycle state.
                        proposals:
                          type: integer
                  feedback:
                    type: array
                    items:
                      type: object
                      required:
                        - category
                        - entries
                      properties:
                        category:
                          type: string
                        entries:
                          type: integer
                  quotaWindows:
                    type: array
                    items:
                      type: object
                      required:
                        - scopeKind
                        - scopeRef
                        - windowStart
                        - usedCount
                      properties:
                        scopeKind:
                          type: string
                        scopeRef:
                          type: string
                        windowStart:
                          type: string
                        usedCount:
                          type: integer
              example:
                windowDays: 7
                daily:
                  - day: 2026-07-25T00:00:00Z
                    directTurns: 42
                    onlineTurns: 17
                    declinedTurns: 2
                    quotaRefused: 0
                    providerFailures: 1
                    acceptedAnswers: 55
                    averageLatencyMs: 1840
                byFamily:
                  - questionFamily: CURRENT_PAYOFF
                    answerPath: DIRECT
                    answerStatus: GROUNDED
                    turns: 28
                    suppressed: false
                usageBuckets:
                  - bucket: ONLINE
                    turns: 17
                actionOutcomes:
                  - capabilityCode: SAVE_CASE_NOTE
                    status: CONFIRMED
                    proposals: 6
                feedback:
                  - category: HELPFUL
                    entries: 12
                quotaWindows:
                  - scopeKind: TENANT
                    scopeRef: default
                    windowStart: 2026-07-25T00:00:00Z
                    usedCount: 59
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
  /v1/servicing/email-threads:
    get:
      tags:
        - Email threads
      operationId: listEmailThreads
      summary: List email threads
      description: Lists email conversation threads with bounded previews, newest activity first. Message bodies never appear
        in list projections; content is a separate audited read.
      x-permission: READ_SERVICING_INTERACTION
      x-idempotent: false
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: customerRef
          in: query
          required: false
          description: Exact customer reference.
          schema:
            type: string
        - name: actionNeeded
          in: query
          required: false
          description: Filter threads that owe a reply.
          schema:
            type: boolean
        - name: limit
          in: query
          required: false
          description: Maximum threads to return.
          schema:
            type: integer
            minimum: 1
            maximum: 200
            default: 50
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: array
                items:
                  type: object
                  required:
                    - threadId
                    - customerRef
                    - caseId
                    - subject
                    - status
                    - associationState
                    - associationEvidence
                    - mailboxMode
                    - actionNeeded
                    - lastMessageAt
                    - messageCount
                    - latestPreview
                    - latestDirection
                  properties:
                    threadId:
                      type: integer
                    customerRef:
                      type: string
                    caseId:
                      type: integer
                      description: Stable opaque servicing case identifier.
                    subject:
                      type: string
                    status:
                      type: string
                      description: Current normalized lifecycle state.
                    associationState:
                      type: string
                    associationEvidence:
                      type: string
                    mailboxMode:
                      type: string
                    actionNeeded:
                      type: boolean
                    lastMessageAt:
                      type: string
                      format: date-time
                    messageCount:
                      type: integer
                    latestPreview:
                      type: string
                    latestDirection:
                      type: string
              example:
                - threadId: 3501
                  customerRef: "123"
                  caseId: 1001
                  subject: Question about my July payment
                  status: ACTIVE
                  associationState: EXACT_VERIFIED_CONTACT
                  associationEvidence: VERIFIED_EMAIL_CONTACT
                  mailboxMode: MONITORED
                  actionNeeded: true
                  lastMessageAt: 2026-07-25T18:40:00Z
                  messageCount: 3
                  latestPreview: Thanks, could you confirm the payment posted?
                  latestDirection: INBOUND
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
  /v1/servicing/email-threads/{threadId}:
    get:
      tags:
        - Email threads
      operationId: getEmailThread
      summary: Retrieve an email thread
      description: Returns one thread projection including association evidence, acknowledgement state, and the server-derived
        replyable flag. Replies are possible only on an open thread with an exact verified contact association.
      x-permission: READ_SERVICING_INTERACTION
      x-idempotent: false
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: threadId
          in: path
          required: true
          description: Stable opaque thread identifier.
          schema:
            type: string
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - threadId
                  - customerRef
                  - caseId
                  - subject
                  - status
                  - associationState
                  - associationEvidence
                  - mailboxMode
                  - actionNeeded
                  - lastMessageAt
                  - messageCount
                  - closedAt
                  - reopenedAt
                  - acknowledgementPolicyCode
                  - acknowledgementSentAt
                  - replyable
                properties:
                  threadId:
                    type: integer
                  customerRef:
                    type: string
                  caseId:
                    type: integer
                    description: Stable opaque servicing case identifier.
                  subject:
                    type: string
                  status:
                    type: string
                    description: Current normalized lifecycle state.
                  associationState:
                    type: string
                  associationEvidence:
                    type: string
                  mailboxMode:
                    type: string
                  actionNeeded:
                    type: boolean
                  lastMessageAt:
                    type: string
                    format: date-time
                  messageCount:
                    type: integer
                  closedAt:
                    type: string
                    format: date-time
                  reopenedAt:
                    type: string
                    format: date-time
                  acknowledgementPolicyCode:
                    type: string
                  acknowledgementSentAt:
                    type: string
                    format: date-time
                  replyable:
                    type: boolean
              example:
                threadId: 3501
                customerRef: "123"
                caseId: 1001
                subject: Question about my July payment
                status: ACTIVE
                associationState: EXACT_VERIFIED_CONTACT
                associationEvidence: VERIFIED_EMAIL_CONTACT
                mailboxMode: MONITORED
                actionNeeded: true
                lastMessageAt: 2026-07-25T18:40:00Z
                messageCount: 3
                closedAt: null
                reopenedAt: null
                acknowledgementPolicyCode: SAFE_ACK
                acknowledgementSentAt: 2026-07-25T18:21:00Z
                replyable: true
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
  /v1/servicing/email-threads/{threadId}/messages:
    get:
      tags:
        - Email threads
      operationId: listEmailThreadMessages
      summary: List email thread messages
      description: Lists message headers, delivery state, and bounded previews for one thread, oldest first. Bodies come from
        the separate content read.
      x-permission: READ_SERVICING_INTERACTION
      x-idempotent: false
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: threadId
          in: path
          required: true
          description: Stable opaque thread identifier.
          schema:
            type: string
        - name: limit
          in: query
          required: false
          description: Maximum messages to return.
          schema:
            type: integer
            minimum: 1
            maximum: 200
            default: 100
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: array
                items:
                  type: object
                  required:
                    - messageId
                    - direction
                    - status
                    - fromRef
                    - subject
                    - preview
                    - hasContent
                    - threadingEvidence
                    - contentSource
                    - mailboxMode
                    - autoSubmitted
                    - bulkOrList
                    - attachmentCount
                    - createdAt
                  properties:
                    messageId:
                      type: integer
                    direction:
                      type: string
                    status:
                      type: string
                      description: Current normalized lifecycle state.
                    fromRef:
                      type: string
                    subject:
                      type: string
                    preview:
                      type: string
                    hasContent:
                      type: boolean
                    threadingEvidence:
                      type: string
                    contentSource:
                      type: string
                    mailboxMode:
                      type: string
                    autoSubmitted:
                      type: boolean
                    bulkOrList:
                      type: boolean
                    attachmentCount:
                      type: integer
                    createdAt:
                      type: string
                      format: date-time
              example:
                - messageId: 3601
                  direction: INBOUND
                  status: RECEIVED
                  fromRef: customer@example.invalid
                  subject: Question about my July payment
                  preview: Hi, I paid on the 20th but my balance looks unchanged.
                  hasContent: true
                  threadingEvidence: HEADER_IN_REPLY_TO
                  contentSource: null
                  mailboxMode: MONITORED
                  autoSubmitted: false
                  bulkOrList: false
                  attachmentCount: 0
                  createdAt: 2026-07-25T18:20:00Z
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
  /v1/servicing/email-threads/{threadId}/messages/{messageId}/content:
    get:
      tags:
        - Email threads
      operationId: readEmailMessageContent
      summary: Read an email message body
      description: Returns one message’s no-store body after ordinary and sensitive authorization; this is the audited call
        that discloses content. The message is scoped by its thread, so a message identifier alone opens nothing.
      x-permission: READ_SERVICING_INTERACTION&READ_SERVICING_INTERACTION_SENSITIVE
      x-idempotent: false
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: threadId
          in: path
          required: true
          description: Stable opaque thread identifier.
          schema:
            type: string
        - name: messageId
          in: path
          required: true
          description: Stable opaque message identifier.
          schema:
            type: string
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - messageId
                  - threadId
                  - direction
                  - subject
                  - charset
                  - contentType
                  - bodyText
                properties:
                  messageId:
                    type: integer
                  threadId:
                    type: integer
                  direction:
                    type: string
                  subject:
                    type: string
                  charset:
                    type: string
                  contentType:
                    type: string
                  bodyText:
                    type: string
              example:
                messageId: 3601
                threadId: 3501
                direction: INBOUND
                subject: Question about my July payment
                charset: UTF-8
                contentType: text/plain
                bodyText: Hi, I paid on the 20th but my balance looks unchanged. Can you confirm the payment posted?
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
  /v1/servicing/email-threads/{threadId}/reply:
    post:
      tags:
        - Email threads
      operationId: replyToEmailThread
      summary: Reply to an email thread
      description: Queues one governed reply on a replyable thread and returns 202 with status QUEUED; nothing claims the
        provider has the message yet. Transport addressing and threading headers are server-owned and cannot be
        supplied, and contentSource is HUMAN, HUMAN_APPROVED, or SYSTEM.
      x-permission: SEND_SERVICING_INTERACTION
      x-idempotent: true
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: threadId
          in: path
          required: true
          description: Stable opaque thread identifier.
          schema:
            type: string
        - name: Idempotency-Key
          in: header
          required: false
          description: Optional replay key for this logical mutation. Omission creates a fresh server-owned key for this attempt;
            blank, repeated, or longer-than-50-character values are rejected.
          schema:
            type: string
            minLength: 1
            maxLength: 50
      responses:
        "202":
          description: Accepted for asynchronous processing.
          content:
            application/json:
              schema:
                type: object
                required:
                  - threadId
                  - messageId
                  - status
                  - senderProfileCode
                  - fromAddress
                  - mailboxMode
                  - preparationDecisionId
                  - resourceId
                properties:
                  threadId:
                    type: integer
                  messageId:
                    type: integer
                  status:
                    type: string
                    description: Current normalized lifecycle state.
                  senderProfileCode:
                    type: string
                  fromAddress:
                    type: string
                  mailboxMode:
                    type: string
                  preparationDecisionId:
                    type: integer
                  resourceId:
                    type: integer
              example:
                threadId: 3501
                messageId: 3602
                status: QUEUED
                senderProfileCode: SERVICING_PRIMARY
                fromAddress: servicing@example.invalid
                mailboxMode: MONITORED
                preparationDecisionId: 6118
                resourceId: 3602
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
        "409":
          $ref: "#/components/responses/Servicing409Error"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - body
              properties:
                caseId:
                  type: integer
                  description: Stable opaque servicing case identifier.
                reasonCode:
                  type: string
                  description: Configured structured reason code.
                subject:
                  type: string
                body:
                  type: string
                contentSource:
                  type: string
                attachmentEvidenceIds:
                  type: array
                  items:
                    type: integer
                sensitive:
                  type: boolean
                acknowledgeUnmonitored:
                  type: boolean
              example:
                caseId: 1001
                reasonCode: PAYMENT_QUESTION
                subject: "Re: Question about my July payment"
                body: Your payment posted on July 21 and your balance is current.
                contentSource: HUMAN
                attachmentEvidenceIds:
                  - 7001
                sensitive: false
                acknowledgeUnmonitored: false
            example:
              caseId: 1001
              reasonCode: PAYMENT_QUESTION
              subject: "Re: Question about my July payment"
              body: Your payment posted on July 21 and your balance is current.
              contentSource: HUMAN
              attachmentEvidenceIds:
                - 7001
              sensitive: false
              acknowledgeUnmonitored: false
  /v1/servicing/interactions/{interactionId}/case-links:
    post:
      tags:
        - Interactions
      operationId: linkInteractionCase
      summary: Link an interaction to a case
      description: Links an interaction to a case with an operator-recorded reason, and sets the primary case when the
        interaction had none.
      x-permission: ASSOCIATE_SERVICING_INTERACTION
      x-idempotent: true
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: interactionId
          in: path
          required: true
          description: Positive numeric interaction identifier.
          schema:
            type: integer
            format: int64
            minimum: 1
        - name: Idempotency-Key
          in: header
          required: false
          description: Optional replay key for this logical mutation. Omission creates a fresh server-owned key for this attempt;
            blank, repeated, or longer-than-50-character values are rejected.
          schema:
            type: string
            minLength: 1
            maxLength: 50
      responses:
        "201":
          description: Created.
          content:
            application/json:
              schema:
                type: object
                required:
                  - interactionId
                  - changes
                  - resourceId
                properties:
                  interactionId:
                    type: integer
                  changes:
                    type: object
                    required:
                      - caseId
                      - primaryCaseId
                    properties:
                      caseId:
                        type: integer
                        description: Stable opaque servicing case identifier.
                      primaryCaseId:
                        type: integer
                  resourceId:
                    type: integer
              example:
                interactionId: 3001
                changes:
                  caseId: 1001
                  primaryCaseId: 1001
                resourceId: 3001
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
        "409":
          $ref: "#/components/responses/Servicing409Error"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - caseId
              properties:
                caseId:
                  type: integer
                  description: Stable opaque servicing case identifier.
                linkReason:
                  type: string
              example:
                caseId: 1001
                linkReason: Email concerns the open collections case.
            example:
              caseId: 1001
              linkReason: Email concerns the open collections case.
  /v1/servicing/interactions/{interactionId}/customer:
    post:
      tags:
        - Interactions
      operationId: associateInteractionCustomer
      summary: Associate an interaction with a customer
      description: Records the customer an operator identified for an interaction that arrived without a borrower, so
        unknown-intake work can complete. Unknown-intake references are rejected as the target.
      x-permission: ASSOCIATE_SERVICING_INTERACTION
      x-idempotent: true
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: interactionId
          in: path
          required: true
          description: Positive numeric interaction identifier.
          schema:
            type: integer
            format: int64
            minimum: 1
        - name: Idempotency-Key
          in: header
          required: false
          description: Optional replay key for this logical mutation. Omission creates a fresh server-owned key for this attempt;
            blank, repeated, or longer-than-50-character values are rejected.
          schema:
            type: string
            minLength: 1
            maxLength: 50
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - interactionId
                  - customerRef
                  - resourceId
                properties:
                  interactionId:
                    type: integer
                  customerRef:
                    type: string
                  resourceId:
                    type: integer
              example:
                interactionId: 3001
                customerRef: "123"
                resourceId: 3001
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
        "409":
          $ref: "#/components/responses/Servicing409Error"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - customerRef
              properties:
                customerRef:
                  type: string
              example:
                customerRef: "123"
            example:
              customerRef: "123"
  /v1/servicing/customers/{customerRef}/contact-points/{contactPointId}/deliver:
    post:
      tags:
        - Interactions
      operationId: deliverContactPoint
      summary: Deliver a portal contact-point message
      description: Sends one closed-template portal message (PORTAL_INVITE, PORTAL_OTP, PORTAL_STEP_UP, PORTAL_PASSWORD_RESET,
        or PORTAL_SECURITY_ALERT) to a customer-owned verified email contact point, answering with a delivery reference
        and masked display and never the address. Refusals return 422 with a reason such as NOT_VERIFIED or
        UNSUPPORTED_PURPOSE.
      x-permission: DELIVER_PORTAL_CONTACT_POINT
      x-idempotent: true
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: customerRef
          in: path
          required: true
          description: Stable opaque customerRef 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 replay key for this logical mutation. Omission creates a fresh server-owned key for this attempt;
            blank, repeated, or longer-than-50-character values are rejected.
          schema:
            type: string
            minLength: 1
            maxLength: 50
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - deliveryRef
                  - status
                  - maskedDisplay
                properties:
                  deliveryRef:
                    type: string
                  status:
                    type: string
                    description: Current normalized lifecycle state.
                  maskedDisplay:
                    type: string
              example:
                deliveryRef: LE-PDL-8f14e45f-ce95-4d0d-9a76-1b3f5a2c9d10
                status: QUEUED
                maskedDisplay: m•••a@example.invalid
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
        "409":
          $ref: "#/components/responses/Servicing409Error"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - purposeCode
              properties:
                purposeCode:
                  type: string
                variables:
                  type: object
                  required:
                    - inviteUrl
                    - expiresAt
                  properties:
                    inviteUrl:
                      type: string
                    expiresAt:
                      type: string
                      format: date-time
              example:
                purposeCode: PORTAL_INVITE
                variables:
                  inviteUrl: https://portal.example.invalid/invite/opaque-token
                  expiresAt: 2026-07-26T18:40:00Z
            example:
              purposeCode: PORTAL_INVITE
              variables:
                inviteUrl: https://portal.example.invalid/invite/opaque-token
                expiresAt: 2026-07-26T18:40:00Z
  /v1/servicing/customers/{customerRef}/contact-points/{contactPointId}/match:
    post:
      tags:
        - Interactions
      operationId: matchContactPoint
      summary: Match a portal contact point
      description: Confirms whether a candidate value matches the stored contact point and answers with a single boolean, so
        the portal can verify a contact without ever reading the address. Unknown references and other customers’
        references both answer false.
      x-permission: MATCH_PORTAL_CONTACT_POINT
      x-idempotent: true
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: customerRef
          in: path
          required: true
          description: Stable opaque customerRef 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 replay key for this logical mutation. Omission creates a fresh server-owned key for this attempt;
            blank, repeated, or longer-than-50-character values are rejected.
          schema:
            type: string
            minLength: 1
            maxLength: 50
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - matches
                properties:
                  matches:
                    type: boolean
              example:
                matches: true
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
        "409":
          $ref: "#/components/responses/Servicing409Error"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - candidate
              properties:
                candidate:
                  type: string
                  format: date
              example:
                candidate: maria@example.invalid
            example:
              candidate: maria@example.invalid
  /v1/servicing/cases/{caseId}/scheduled-callbacks:
    post:
      tags:
        - Scheduled callbacks
      operationId: createScheduledCallback
      summary: Schedule a callback on a case
      description: Records a borrower-promised callback window as one scheduled task and one scheduled interaction created
        together. The case supplies the customer and loan, the window must be a future 5–120 minute span in the
        borrower’s known time zone, an outside-hours window requires the borrower’s recorded agreement, and a case holds
        at most one unresolved callback.
      x-permission: CREATE_SERVICING_SCHEDULED_CALLBACK
      x-idempotent: true
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: caseId
          in: path
          required: true
          description: Positive numeric case identifier.
          schema:
            type: integer
            format: int64
            minimum: 1
        - name: Idempotency-Key
          in: header
          required: false
          description: Optional replay key for this logical mutation. Omission creates a fresh server-owned key for this attempt;
            blank, repeated, or longer-than-50-character values are rejected.
          schema:
            type: string
            minLength: 1
            maxLength: 50
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - taskId
                  - interactionId
                  - caseId
                  - status
                  - windowStart
                  - windowEnd
                  - scheduledZoneId
                properties:
                  taskId:
                    type: integer
                  interactionId:
                    type: integer
                  caseId:
                    type: integer
                    description: Stable opaque servicing case identifier.
                  status:
                    type: string
                    description: Current normalized lifecycle state.
                  windowStart:
                    type: string
                  windowEnd:
                    type: string
                  scheduledZoneId:
                    type: string
              example:
                taskId: 2001
                interactionId: 3001
                caseId: 1001
                status: SCHEDULED
                windowStart: 2026-07-26T15:00:00Z
                windowEnd: 2026-07-26T15:30:00Z
                scheduledZoneId: America/Chicago
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
        "409":
          $ref: "#/components/responses/Servicing409Error"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - windowStart
                - windowEnd
                - contactPointRef
                - reasonCode
              properties:
                windowStart:
                  type: string
                windowEnd:
                  type: string
                contactPointRef:
                  type: string
                reasonCode:
                  type: string
                  description: Configured structured reason code.
                summary:
                  type: string
                outsideHoursAgreement:
                  type: object
                  required:
                    - borrowerAgreed
                    - evidenceSource
                    - evidenceRef
                  properties:
                    borrowerAgreed:
                      type: boolean
                    evidenceSource:
                      type: string
                    evidenceRef:
                      type: string
              example:
                windowStart: 2026-07-26T15:00:00Z
                windowEnd: 2026-07-26T15:30:00Z
                contactPointRef: phone-1
                reasonCode: COLLECTIONS_FOLLOW_UP
                summary: Customer asked to be called back about the missed payment.
                outsideHoursAgreement:
                  borrowerAgreed: true
                  evidenceSource: CALL_RECORDING
                  evidenceRef: call-transcript-731
            example:
              windowStart: 2026-07-26T15:00:00Z
              windowEnd: 2026-07-26T15:30:00Z
              contactPointRef: phone-1
              reasonCode: COLLECTIONS_FOLLOW_UP
              summary: Customer asked to be called back about the missed payment.
              outsideHoursAgreement:
                borrowerAgreed: true
                evidenceSource: CALL_RECORDING
                evidenceRef: call-transcript-731
    get:
      tags:
        - Scheduled callbacks
      operationId: listCaseScheduledCallbacks
      summary: List callbacks on a case
      description: Returns every callback on the case, newest promise first, joining the task and interaction into one record.
        The promise indicator (SCHEDULED, IN_WINDOW, AT_RISK, MISSED_UNRESOLVED, ON_TIME, LATE, CANCELLED,
        CANCELLED_NO_LONGER_NEEDED) is computed server-side against the promised window.
      x-permission: READ_SERVICING_TASK
      x-idempotent: false
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: caseId
          in: path
          required: true
          description: Positive numeric case identifier.
          schema:
            type: integer
            format: int64
            minimum: 1
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: array
                items:
                  type: object
                  required:
                    - taskId
                    - caseId
                    - interactionId
                    - status
                    - interactionStatus
                    - priority
                    - queueCode
                    - summary
                    - reasonCode
                    - contactPointRef
                    - windowStart
                    - windowEnd
                    - scheduledZoneId
                    - availableAt
                    - completeBy
                    - reservedByWorkerId
                    - reservedByWorkerName
                    - reservationExpiresAt
                    - promiseIndicator
                  properties:
                    taskId:
                      type: integer
                    caseId:
                      type: integer
                      description: Stable opaque servicing case identifier.
                    interactionId:
                      type: integer
                    status:
                      type: string
                      description: Current normalized lifecycle state.
                    interactionStatus:
                      type: string
                    priority:
                      type: string
                    queueCode:
                      type: string
                    summary:
                      type: string
                    reasonCode:
                      type: string
                      description: Configured structured reason code.
                    contactPointRef:
                      type: string
                    windowStart:
                      type: string
                    windowEnd:
                      type: string
                    scheduledZoneId:
                      type: string
                    availableAt:
                      type: string
                      format: date-time
                    completeBy:
                      type: string
                    reservedByWorkerId:
                      type: integer
                    reservedByWorkerName:
                      type: string
                    reservationExpiresAt:
                      type: string
                      format: date-time
                    promiseIndicator:
                      type: string
              example:
                - taskId: 2001
                  caseId: 1001
                  interactionId: 3001
                  status: RESERVED
                  interactionStatus: SCHEDULED
                  priority: HIGH
                  queueCode: COLLECTIONS
                  summary: Customer asked to be called back about the missed payment.
                  reasonCode: COLLECTIONS_FOLLOW_UP
                  contactPointRef: phone-1
                  windowStart: 2026-07-26T15:00:00Z
                  windowEnd: 2026-07-26T15:30:00Z
                  scheduledZoneId: America/Chicago
                  availableAt: 2026-07-26T15:00:00Z
                  completeBy: 2026-07-26T15:30:00Z
                  reservedByWorkerId: 4101
                  reservedByWorkerName: Maria Agent
                  reservationExpiresAt: 2026-07-26T15:05:00Z
                  promiseIndicator: IN_WINDOW
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
  /v1/servicing/scheduled-callbacks/{taskId}:
    get:
      tags:
        - Scheduled callbacks
      operationId: getScheduledCallback
      summary: Retrieve a scheduled callback
      description: Returns one callback with its schedule-change history and its allocation-offer history. Window times carry
        the borrower’s scheduled zone; completeBy is the internal task deadline, kept separate from the promised window.
      x-permission: READ_SERVICING_TASK
      x-idempotent: false
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: taskId
          in: path
          required: true
          description: Positive numeric task identifier.
          schema:
            type: integer
            format: int64
            minimum: 1
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - taskId
                  - caseId
                  - interactionId
                  - status
                  - interactionStatus
                  - priority
                  - queueCode
                  - summary
                  - reasonCode
                  - contactPointRef
                  - windowStart
                  - windowEnd
                  - scheduledZoneId
                  - availableAt
                  - completeBy
                  - reservedByWorkerId
                  - reservedByWorkerName
                  - reservationExpiresAt
                  - promiseIndicator
                  - scheduleHistory
                  - reservationHistory
                properties:
                  taskId:
                    type: integer
                  caseId:
                    type: integer
                    description: Stable opaque servicing case identifier.
                  interactionId:
                    type: integer
                  status:
                    type: string
                    description: Current normalized lifecycle state.
                  interactionStatus:
                    type: string
                  priority:
                    type: string
                  queueCode:
                    type: string
                  summary:
                    type: string
                  reasonCode:
                    type: string
                    description: Configured structured reason code.
                  contactPointRef:
                    type: string
                  windowStart:
                    type: string
                  windowEnd:
                    type: string
                  scheduledZoneId:
                    type: string
                  availableAt:
                    type: string
                    format: date-time
                  completeBy:
                    type: string
                  reservedByWorkerId:
                    type: integer
                  reservedByWorkerName:
                    type: string
                  reservationExpiresAt:
                    type: string
                    format: date-time
                  promiseIndicator:
                    type: string
                  scheduleHistory:
                    type: array
                    items:
                      type: object
                      required:
                        - changeType
                        - newWindowStart
                        - newWindowEnd
                        - newZoneId
                        - reasonCode
                        - actorType
                        - actorRef
                        - consentReplaced
                        - reservationReleased
                        - at
                      properties:
                        changeType:
                          type: string
                        newWindowStart:
                          type: string
                        newWindowEnd:
                          type: string
                        newZoneId:
                          type: string
                        reasonCode:
                          type: string
                          description: Configured structured reason code.
                        actorType:
                          type: string
                        actorRef:
                          type: string
                        consentReplaced:
                          type: boolean
                        reservationReleased:
                          type: boolean
                        at:
                          type: string
                          format: date-time
                  reservationHistory:
                    type: array
                    items:
                      type: object
                      required:
                        - workerId
                        - workerName
                        - state
                        - offeredAt
                        - expiresAt
                        - trigger
                        - reason
                        - candidateCount
                      properties:
                        workerId:
                          type: integer
                        workerName:
                          type: string
                        state:
                          type: string
                        offeredAt:
                          type: string
                          format: date-time
                        expiresAt:
                          type: string
                          format: date-time
                        trigger:
                          type: string
                        reason:
                          type: string
                        candidateCount:
                          type: integer
              example:
                taskId: 2001
                caseId: 1001
                interactionId: 3001
                status: RESERVED
                interactionStatus: SCHEDULED
                priority: HIGH
                queueCode: COLLECTIONS
                summary: Customer asked to be called back about the missed payment.
                reasonCode: COLLECTIONS_FOLLOW_UP
                contactPointRef: phone-1
                windowStart: 2026-07-26T15:00:00Z
                windowEnd: 2026-07-26T15:30:00Z
                scheduledZoneId: America/Chicago
                availableAt: 2026-07-26T15:00:00Z
                completeBy: 2026-07-26T15:30:00Z
                reservedByWorkerId: 4101
                reservedByWorkerName: Maria Agent
                reservationExpiresAt: 2026-07-26T15:05:00Z
                promiseIndicator: IN_WINDOW
                scheduleHistory:
                  - changeType: SCHEDULED
                    newWindowStart: 2026-07-26T15:00:00Z
                    newWindowEnd: 2026-07-26T15:30:00Z
                    newZoneId: America/Chicago
                    reasonCode: BORROWER_REQUEST
                    actorType: HUMAN
                    actorRef: "4101"
                    consentReplaced: false
                    reservationReleased: false
                    at: 2026-07-25T18:40:00Z
                reservationHistory:
                  - workerId: 4101
                    workerName: Maria Agent
                    state: OPEN
                    offeredAt: 2026-07-26T15:00:05Z
                    expiresAt: 2026-07-26T15:05:00Z
                    trigger: TASK_ACTIVATED
                    reason: Carrying the least work of 3 available eligible workers
                    candidateCount: 3
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
  /v1/servicing/scheduled-callbacks/{taskId}/reschedule:
    post:
      tags:
        - Scheduled callbacks
      operationId: rescheduleScheduledCallback
      summary: Reschedule a callback
      description: Moves an unstarted promise to a new window on the same task and interaction, releasing any live reservation
        and replacing window-scoped outside-hours consent. A callback whose call has started cannot be rescheduled;
        record its disposition instead.
      x-permission: RESCHEDULE_SERVICING_SCHEDULED_CALLBACK
      x-idempotent: true
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: taskId
          in: path
          required: true
          description: Positive numeric task identifier.
          schema:
            type: integer
            format: int64
            minimum: 1
        - name: Idempotency-Key
          in: header
          required: false
          description: Optional replay key for this logical mutation. Omission creates a fresh server-owned key for this attempt;
            blank, repeated, or longer-than-50-character values are rejected.
          schema:
            type: string
            minLength: 1
            maxLength: 50
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - taskId
                  - interactionId
                  - caseId
                  - status
                  - windowStart
                  - windowEnd
                  - scheduledZoneId
                properties:
                  taskId:
                    type: integer
                  interactionId:
                    type: integer
                  caseId:
                    type: integer
                    description: Stable opaque servicing case identifier.
                  status:
                    type: string
                    description: Current normalized lifecycle state.
                  windowStart:
                    type: string
                  windowEnd:
                    type: string
                  scheduledZoneId:
                    type: string
              example:
                taskId: 2001
                interactionId: 3001
                caseId: 1001
                status: SCHEDULED
                windowStart: 2026-07-27T16:00:00Z
                windowEnd: 2026-07-27T16:30:00Z
                scheduledZoneId: America/Chicago
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
        "409":
          $ref: "#/components/responses/Servicing409Error"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - windowStart
                - windowEnd
                - reasonCode
              properties:
                windowStart:
                  type: string
                windowEnd:
                  type: string
                reasonCode:
                  type: string
                  description: Configured structured reason code.
                note:
                  type: string
              example:
                windowStart: 2026-07-27T16:00:00Z
                windowEnd: 2026-07-27T16:30:00Z
                reasonCode: BORROWER_REQUEST
                note: Customer asked to move the call to tomorrow afternoon.
            example:
              windowStart: 2026-07-27T16:00:00Z
              windowEnd: 2026-07-27T16:30:00Z
              reasonCode: BORROWER_REQUEST
              note: Customer asked to move the call to tomorrow afternoon.
  /v1/servicing/scheduled-callbacks/{taskId}/cancel:
    post:
      tags:
        - Scheduled callbacks
      operationId: cancelScheduledCallback
      summary: Cancel a callback
      description: "Cancels an unstarted promise outright, revokes any window-scoped consent, and records the change in the
        schedule history. Recorded as cancelled rather than completed: nobody called."
      x-permission: CANCEL_SERVICING_SCHEDULED_CALLBACK
      x-idempotent: true
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: taskId
          in: path
          required: true
          description: Positive numeric task identifier.
          schema:
            type: integer
            format: int64
            minimum: 1
        - name: Idempotency-Key
          in: header
          required: false
          description: Optional replay key for this logical mutation. Omission creates a fresh server-owned key for this attempt;
            blank, repeated, or longer-than-50-character values are rejected.
          schema:
            type: string
            minLength: 1
            maxLength: 50
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - taskId
                  - interactionId
                  - caseId
                  - status
                  - windowStart
                  - windowEnd
                  - scheduledZoneId
                properties:
                  taskId:
                    type: integer
                  interactionId:
                    type: integer
                  caseId:
                    type: integer
                    description: Stable opaque servicing case identifier.
                  status:
                    type: string
                    description: Current normalized lifecycle state.
                  windowStart:
                    type: string
                  windowEnd:
                    type: string
                  scheduledZoneId:
                    type: string
              example:
                taskId: 2001
                interactionId: 3001
                caseId: 1001
                status: CANCELLED
                windowStart: 2026-07-26T15:00:00Z
                windowEnd: 2026-07-26T15:30:00Z
                scheduledZoneId: America/Chicago
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
        "409":
          $ref: "#/components/responses/Servicing409Error"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - reasonCode
              properties:
                reasonCode:
                  type: string
                  description: Configured structured reason code.
                note:
                  type: string
              example:
                reasonCode: CUSTOMER_CANCELLED
                note: Customer withdrew the callback request.
            example:
              reasonCode: CUSTOMER_CANCELLED
              note: Customer withdrew the callback request.
  /v1/servicing/scheduled-callbacks/{taskId}/close-without-calling:
    post:
      tags:
        - Scheduled callbacks
      operationId: closeScheduledCallbackWithoutCalling
      summary: Close a callback without calling
      description: Closes a promise nobody needs any more — the payment landed, the question was answered elsewhere — without
        inventing a call. reasonCode must be one of PAYMENT_RECEIVED, RESOLVED_ELSEWHERE, CUSTOMER_CANCELLED,
        DUPLICATE_CALLBACK, CASE_RESOLVED, or OTHER (OTHER requires a note); the callback resolves as CANCELLED with
        outcome CALL_NO_LONGER_NEEDED.
      x-permission: CLOSE_SERVICING_SCHEDULED_CALLBACK
      x-idempotent: true
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: taskId
          in: path
          required: true
          description: Positive numeric task identifier.
          schema:
            type: integer
            format: int64
            minimum: 1
        - name: Idempotency-Key
          in: header
          required: false
          description: Optional replay key for this logical mutation. Omission creates a fresh server-owned key for this attempt;
            blank, repeated, or longer-than-50-character values are rejected.
          schema:
            type: string
            minLength: 1
            maxLength: 50
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - taskId
                  - interactionId
                  - caseId
                  - status
                  - windowStart
                  - windowEnd
                  - scheduledZoneId
                properties:
                  taskId:
                    type: integer
                  interactionId:
                    type: integer
                  caseId:
                    type: integer
                    description: Stable opaque servicing case identifier.
                  status:
                    type: string
                    description: Current normalized lifecycle state.
                  windowStart:
                    type: string
                  windowEnd:
                    type: string
                  scheduledZoneId:
                    type: string
              example:
                taskId: 2001
                interactionId: 3001
                caseId: 1001
                status: CANCELLED
                windowStart: 2026-07-26T15:00:00Z
                windowEnd: 2026-07-26T15:30:00Z
                scheduledZoneId: America/Chicago
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
        "409":
          $ref: "#/components/responses/Servicing409Error"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - reasonCode
              properties:
                reasonCode:
                  type: string
                  description: Configured structured reason code.
                note:
                  type: string
              example:
                reasonCode: PAYMENT_RECEIVED
                note: The payment posted before the window opened.
            example:
              reasonCode: PAYMENT_RECEIVED
              note: The payment posted before the window opened.
  /v1/servicing/scheduled-callbacks/{taskId}/start-call:
    post:
      tags:
        - Scheduled callbacks
      operationId: startScheduledCallbackCall
      summary: Start the promised call
      description: Places the promised call under a compliance decision evaluated at this instant, not when the promise was
        made. Only the accepted assigned worker may start it; a placed call moves the task to IN_PROGRESS and can return
        a short-lived dial grant, while a blocked one returns the blocking reason instead.
      x-permission: START_SERVICING_SCHEDULED_CALLBACK
      x-idempotent: true
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: taskId
          in: path
          required: true
          description: Positive numeric task identifier.
          schema:
            type: integer
            format: int64
            minimum: 1
        - name: Idempotency-Key
          in: header
          required: false
          description: Optional replay key for this logical mutation. Omission creates a fresh server-owned key for this attempt;
            blank, repeated, or longer-than-50-character values are rejected.
          schema:
            type: string
            minLength: 1
            maxLength: 50
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - placed
                  - callId
                  - interactionId
                  - status
                  - dialGrantRef
                  - dialGrantExpiresAt
                properties:
                  placed:
                    type: boolean
                  callId:
                    type: integer
                  interactionId:
                    type: integer
                  status:
                    type: string
                    description: Current normalized lifecycle state.
                  dialGrantRef:
                    type: string
                  dialGrantExpiresAt:
                    type: string
                    format: date-time
              example:
                placed: true
                callId: 7001
                interactionId: 3001
                status: DIAL_AUTHORIZED
                dialGrantRef: grant-1f7c9a4b
                dialGrantExpiresAt: 2026-07-26T15:06:00Z
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
        "409":
          $ref: "#/components/responses/Servicing409Error"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - contactPointRef
                - recordingRequested
              properties:
                contactPointRef:
                  type: string
                recordingRequested:
                  type: boolean
              example:
                contactPointRef: phone-1
                recordingRequested: false
            example:
              contactPointRef: phone-1
              recordingRequested: false
  /v1/servicing/scheduled-callbacks/{taskId}/disposition:
    post:
      tags:
        - Scheduled callbacks
      operationId: recordScheduledCallbackDisposition
      summary: Record the call disposition
      description: Records what happened on the call and resolves the promise with it in one transaction. outcomeCode is the
        closed set SPOKE_TO_BORROWER, NO_CONTACT, or WRONG_NUMBER — WRONG_NUMBER returns the task to its worker
        unresolved — and an optional followUp window schedules a fresh promise rather than editing the attempted one.
      x-permission: DISPOSITION_SERVICING_SCHEDULED_CALLBACK
      x-idempotent: true
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: taskId
          in: path
          required: true
          description: Positive numeric task identifier.
          schema:
            type: integer
            format: int64
            minimum: 1
        - name: Idempotency-Key
          in: header
          required: false
          description: Optional replay key for this logical mutation. Omission creates a fresh server-owned key for this attempt;
            blank, repeated, or longer-than-50-character values are rejected.
          schema:
            type: string
            minLength: 1
            maxLength: 50
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - taskStatus
                  - interactionStatus
                  - outcomeCode
                  - interactionId
                  - promiseResult
                  - followUpTaskId
                properties:
                  taskStatus:
                    type: string
                  interactionStatus:
                    type: string
                  outcomeCode:
                    type: string
                  interactionId:
                    type: integer
                  promiseResult:
                    type: string
                  followUpTaskId:
                    type: integer
              example:
                taskStatus: COMPLETED
                interactionStatus: ATTEMPTED
                outcomeCode: NO_CONTACT
                interactionId: 3001
                promiseResult: ON_TIME
                followUpTaskId: 2002
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
        "409":
          $ref: "#/components/responses/Servicing409Error"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - outcomeCode
              properties:
                outcomeCode:
                  type: string
                note:
                  type: string
                followUp:
                  type: object
                  required:
                    - windowStart
                    - windowEnd
                    - reasonCode
                  properties:
                    windowStart:
                      type: string
                    windowEnd:
                      type: string
                    reasonCode:
                      type: string
                      description: Configured structured reason code.
              example:
                outcomeCode: NO_CONTACT
                note: Rang out twice inside the window.
                followUp:
                  windowStart: 2026-07-27T16:00:00Z
                  windowEnd: 2026-07-27T16:30:00Z
                  reasonCode: COLLECTIONS_FOLLOW_UP
            example:
              outcomeCode: NO_CONTACT
              note: Rang out twice inside the window.
              followUp:
                windowStart: 2026-07-27T16:00:00Z
                windowEnd: 2026-07-27T16:30:00Z
                reasonCode: COLLECTIONS_FOLLOW_UP
  /v1/servicing/voice/dial-grants/redeem:
    post:
      tags:
        - Voice
      operationId: redeemDialGrant
      summary: Redeem a dial grant
      description: Exchanges a single-use, sixty-second dial grant for the number it authorizes. Only the worker the grant
        names may redeem it, the number appears in this response body and nowhere else — never in a table, log, event,
        or URL — and refusals return a named refusalCode to act on.
      x-permission: SEND_SERVICING_INTERACTION
      x-idempotent: true
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: Idempotency-Key
          in: header
          required: false
          description: Optional replay key for this logical mutation. Omission creates a fresh server-owned key for this attempt;
            blank, repeated, or longer-than-50-character values are rejected.
          schema:
            type: string
            minLength: 1
            maxLength: 50
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - callId
                  - gatewayAgentRef
                  - dialEndpoint
                  - maskedContact
                properties:
                  callId:
                    type: integer
                  gatewayAgentRef:
                    type: string
                  dialEndpoint:
                    type: string
                  maskedContact:
                    type: string
              example:
                callId: 7001
                gatewayAgentRef: connect-agent-4101
                dialEndpoint: "+15005550006"
                maskedContact: "***0006"
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
        "409":
          $ref: "#/components/responses/Servicing409Error"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - grantRef
              properties:
                grantRef:
                  type: string
              example:
                grantRef: grant-1f7c9a4b
            example:
              grantRef: grant-1f7c9a4b
  /v1/servicing/voice-provider/control/api/v1/workflow-versions:
    get:
      tags:
        - Voice
      operationId: listVoiceWorkflowDefinitions
      summary: List voice workflow definitions
      description: "Authenticated pass-through to the voice provider control plane: the read-only workflow definition index.
        The response is the provider’s own shape, forwarded verbatim with the provider credential held server-side."
      x-permission: READ_SERVICING_VOICE_PROVIDER
      x-idempotent: false
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: array
                items:
                  type: object
                  required:
                    - workflow_id
                    - active_version
                    - version_count
                    - last_updated
                  properties:
                    workflow_id:
                      type: string
                    active_version:
                      type: integer
                    version_count:
                      type: integer
                    last_updated:
                      type: string
              example:
                - workflow_id: collections_demo_v2
                  active_version: 3
                  version_count: 3
                  last_updated: 2026-07-25T18:30:00Z
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
  /v1/servicing/voice-provider/control/api/v1/workflow-versions/{workflowId}:
    get:
      tags:
        - Voice
      operationId: listVoiceWorkflowVersions
      summary: List versions of a voice workflow
      description: The immutable version history for one provider workflow, forwarded verbatim from the control plane.
      x-permission: READ_SERVICING_VOICE_PROVIDER
      x-idempotent: false
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: workflowId
          in: path
          required: true
          description: Stable opaque workflow identifier.
          schema:
            type: string
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: array
                items:
                  type: object
                  required:
                    - id
                    - workflow_id
                    - version
                    - label
                    - summary
                    - is_active
                    - created_at
                  properties:
                    id:
                      type: integer
                    workflow_id:
                      type: string
                    version:
                      type: integer
                      description: Monotonically increasing resource version.
                    label:
                      type: string
                    summary:
                      type: string
                    is_active:
                      type: boolean
                    created_at:
                      type: string
                      format: date-time
              example:
                - id: 12
                  workflow_id: collections_demo_v2
                  version: 3
                  label: Tightened opening disclosure
                  summary: Reworked the greeting and identification sequence.
                  is_active: true
                  created_at: 2026-07-25T18:30:00Z
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
  /v1/servicing/voice-provider/control/api/v1/workflow-versions/{workflowId}/{version}:
    get:
      tags:
        - Voice
      operationId: getVoiceWorkflowVersion
      summary: Retrieve one voice workflow version
      description: One immutable workflow definition version — pass a version number or the literal active. The full
        node-and-edge definition is the provider’s own shape, forwarded untouched.
      x-permission: READ_SERVICING_VOICE_PROVIDER
      x-idempotent: false
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: workflowId
          in: path
          required: true
          description: Stable opaque workflow identifier.
          schema:
            type: string
        - name: version
          in: path
          required: true
          description: Monotonically increasing resource version.
          schema:
            type: string
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - id
                  - workflow_id
                  - version
                  - label
                  - is_active
                  - created_at
                  - definition
                properties:
                  id:
                    type: integer
                  workflow_id:
                    type: string
                  version:
                    type: integer
                    description: Monotonically increasing resource version.
                  label:
                    type: string
                  is_active:
                    type: boolean
                  created_at:
                    type: string
                    format: date-time
                  definition:
                    type: object
                    required:
                      - id
                      - name
                      - outbound
                      - nodes
                      - edges
                    properties:
                      id:
                        type: string
                      name:
                        type: string
                      outbound:
                        type: boolean
                      nodes:
                        type: array
                        items:
                          type: object
                          required:
                            - id
                            - type
                            - label
                          properties:
                            id:
                              type: string
                            type:
                              type: string
                            label:
                              type: string
                      edges:
                        type: array
                        items:
                          type: object
                          required:
                            - from
                            - to
                            - on
                          properties:
                            from:
                              type: string
                            to:
                              type: string
                            on:
                              type: string
              example:
                id: 12
                workflow_id: collections_demo_v2
                version: 3
                label: Tightened opening disclosure
                is_active: true
                created_at: 2026-07-25T18:30:00Z
                definition:
                  id: collections_demo_v2
                  name: Collections outreach
                  outbound: true
                  nodes:
                    - id: greeting
                      type: conversation
                      label: Greeting and identification
                  edges:
                    - from: greeting
                      to: payment_discussion
                      on: identity_confirmed
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
  /v1/servicing/voice-provider/data/api/v1/calls:
    get:
      tags:
        - Voice
      operationId: listVoiceProviderCalls
      summary: List voice provider calls
      description: Provider data-plane call records behind LendEasy authentication and permissions; path, query, status, and
        body pass through untouched. Call states are connecting, active, done, cancelled, and error.
      x-permission: READ_SERVICING_VOICE_PROVIDER
      x-idempotent: false
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - total
                  - calls
                properties:
                  total:
                    type: integer
                  calls:
                    type: array
                    items:
                      type: object
                      required:
                        - id
                        - state
                        - end_reason
                        - duration_sec
                        - caller_name
                        - ai_summary
                        - started_at
                        - connected_at
                        - completed_at
                        - has_transcript
                      properties:
                        id:
                          type: string
                        state:
                          type: string
                        end_reason:
                          type: string
                        duration_sec:
                          type: integer
                        caller_name:
                          type: string
                        ai_summary:
                          type: string
                        started_at:
                          type: string
                          format: date-time
                        connected_at:
                          type: string
                          format: date-time
                        completed_at:
                          type: string
                          format: date-time
                        has_transcript:
                          type: boolean
              example:
                total: 1
                calls:
                  - id: a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d
                    state: done
                    end_reason: agent_hangup
                    duration_sec: 184
                    caller_name: Maria Agent
                    ai_summary: Borrower confirmed a payment for August 1.
                    started_at: 2026-07-25T18:40:00Z
                    connected_at: 2026-07-25T18:40:06Z
                    completed_at: 2026-07-25T18:43:04Z
                    has_transcript: true
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
  /v1/servicing/voice-provider/data/api/v1/calls/{callId}:
    get:
      tags:
        - Voice
      operationId: getVoiceProviderCall
      summary: Retrieve a voice provider call
      description: One provider call record with its gathered parameters and analytics events, forwarded verbatim. The console
        polls this read while a call is in flight; the post-call summary lands shortly after hangup.
      x-permission: READ_SERVICING_VOICE_PROVIDER
      x-idempotent: false
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: callId
          in: path
          required: true
          description: Stable opaque call identifier.
          schema:
            type: string
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - call
                  - gathered_parameters
                  - analytics
                properties:
                  call:
                    type: object
                    required:
                      - id
                      - state
                      - end_reason
                      - duration_sec
                      - caller_name
                      - ai_summary
                      - started_at
                      - connected_at
                      - completed_at
                      - has_transcript
                    properties:
                      id:
                        type: string
                      state:
                        type: string
                      end_reason:
                        type: string
                      duration_sec:
                        type: integer
                      caller_name:
                        type: string
                      ai_summary:
                        type: string
                      started_at:
                        type: string
                        format: date-time
                      connected_at:
                        type: string
                        format: date-time
                      completed_at:
                        type: string
                        format: date-time
                      has_transcript:
                        type: boolean
                  gathered_parameters:
                    type: array
                    items:
                      type: object
                      required:
                        - name
                        - value
                      properties:
                        name:
                          type: string
                        value:
                          type: string
                  analytics:
                    type: array
                    items:
                      type: object
                      required:
                        - event_name
                        - stage
                        - latency_ms
                        - token_count
                      properties:
                        event_name:
                          type: string
                        stage:
                          type: string
                        latency_ms:
                          type: integer
                        token_count:
                          type: integer
              example:
                call:
                  id: a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d
                  state: done
                  end_reason: agent_hangup
                  duration_sec: 184
                  caller_name: Maria Agent
                  ai_summary: Borrower confirmed a payment for August 1.
                  started_at: 2026-07-25T18:40:00Z
                  connected_at: 2026-07-25T18:40:06Z
                  completed_at: 2026-07-25T18:43:04Z
                  has_transcript: true
                gathered_parameters:
                  - name: promise_date
                    value: 2026-08-01
                analytics:
                  - event_name: llm_response
                    stage: payment_discussion
                    latency_ms: 640
                    token_count: 512
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
  /v1/servicing/voice-provider/data/api/v1/calls/{callId}/{artifact}:
    get:
      tags:
        - Voice
      operationId: getVoiceProviderCallArtifact
      summary: Read a voice call artifact
      description: "Reads one call artifact from the provider data plane: artifacts (the presigned-URL index shown here),
        transcript-text, log, live-log, recording.wav, or audio-timeline. Body and content type are the provider’s,
        forwarded untouched; presigned links expire, so fetch the index fresh before downloading."
      x-permission: READ_SERVICING_VOICE_PROVIDER
      x-idempotent: false
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: callId
          in: path
          required: true
          description: Stable opaque call identifier.
          schema:
            type: string
        - name: artifact
          in: path
          required: true
          description: Stable opaque artifact identifier.
          schema:
            type: string
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - call_id
                  - status
                  - artifacts
                properties:
                  call_id:
                    type: string
                  status:
                    type: string
                    description: Current normalized lifecycle state.
                  artifacts:
                    type: object
                    required:
                      - recording
                      - transcript
                    properties:
                      recording:
                        type: object
                        required:
                          - url
                        properties:
                          url:
                            type: string
                      transcript:
                        type: object
                        required:
                          - url
                        properties:
                          url:
                            type: string
              example:
                call_id: a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d
                status: done
                artifacts:
                  recording:
                    url: https://provider.example/presigned/recording.wav
                  transcript:
                    url: https://provider.example/presigned/transcript.txt
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
  /v1/servicing/voice-provider/data/api/v1/metrics/{workflowId}:
    get:
      tags:
        - Voice
      operationId: getVoiceProviderMetrics
      summary: Read voice workflow metrics
      description: Aggregated provider call metrics for one workflow over the requested range, forwarded verbatim from the
        data plane.
      x-permission: READ_SERVICING_VOICE_PROVIDER
      x-idempotent: false
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: workflowId
          in: path
          required: true
          description: Stable opaque workflow identifier.
          schema:
            type: string
        - name: range
          in: query
          required: false
          description: Aggregation window.
          schema:
            type: string
            enum:
              - 1h
              - 6h
              - 24h
              - 7d
            default: 24h
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - workflow_id
                  - range
                  - row_count
                  - kpis
                  - call_volume_hourly
                  - outcomes
                  - end_reasons
                properties:
                  workflow_id:
                    type: string
                  range:
                    type: string
                  row_count:
                    type: integer
                  kpis:
                    type: object
                    required:
                      - call_count
                      - avg_duration_sec
                      - error_count
                    properties:
                      call_count:
                        type: integer
                      avg_duration_sec:
                        type: number
                      error_count:
                        type: integer
                  call_volume_hourly:
                    type: array
                    items:
                      type: object
                      required:
                        - hour
                        - count
                      properties:
                        hour:
                          type: string
                        count:
                          type: integer
                  outcomes:
                    type: array
                    items:
                      type: object
                      required:
                        - outcome
                        - count
                      properties:
                        outcome:
                          type: string
                        count:
                          type: integer
                  end_reasons:
                    type: array
                    items:
                      type: object
                      required:
                        - end_reason
                        - count
                      properties:
                        end_reason:
                          type: string
                        count:
                          type: integer
              example:
                workflow_id: collections_demo_v2
                range: 24h
                row_count: 42
                kpis:
                  call_count: 42
                  avg_duration_sec: 176.4
                  error_count: 1
                call_volume_hourly:
                  - hour: 2026-07-25T18:00:00Z
                    count: 6
                outcomes:
                  - outcome: promise_to_pay
                    count: 18
                end_reasons:
                  - end_reason: agent_hangup
                    count: 30
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
  /v1/servicing/voice-provider/data/api/v1/workflows:
    get:
      tags:
        - Voice
      operationId: listVoiceProviderWorkflows
      summary: List voice provider workflows
      description: The provider data-plane workflow list that drives the console’s workflow pickers, forwarded verbatim.
      x-permission: READ_SERVICING_VOICE_PROVIDER
      x-idempotent: false
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: array
                items:
                  type: object
                  required:
                    - workflow_id
                    - label
                  properties:
                    workflow_id:
                      type: string
                    label:
                      type: string
              example:
                - workflow_id: collections_demo_v2
                  label: Collections outreach
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
  /v1/servicing/voice-provider/data/workflows/agents:
    get:
      tags:
        - Voice
      operationId: listVoiceAgentTypes
      summary: List voice agent types
      description: The provider’s registry of composable voice agent types and their configuration fields, forwarded verbatim.
        This registry route sits outside the data plane’s /api/v1 tree.
      x-permission: READ_SERVICING_VOICE_PROVIDER
      x-idempotent: false
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: array
                items:
                  type: object
                  required:
                    - type_key
                    - label
                    - description
                    - category
                    - interrupt_eligible_default
                    - config_fields
                  properties:
                    type_key:
                      type: string
                    label:
                      type: string
                    description:
                      type: string
                    category:
                      type: string
                    interrupt_eligible_default:
                      type: boolean
                    config_fields:
                      type: array
                      items:
                        type: object
                        required:
                          - key
                          - label
                          - field_type
                          - scope
                          - required
                        properties:
                          key:
                            type: string
                          label:
                            type: string
                          field_type:
                            type: string
                          scope:
                            type: string
                          required:
                            type: boolean
              example:
                - type_key: payment_negotiator
                  label: Payment negotiator
                  description: Negotiates a payment commitment within configured bounds.
                  category: conversation
                  interrupt_eligible_default: false
                  config_fields:
                    - key: max_installments
                      label: Maximum installments
                      field_type: number
                      scope: workflow
                      required: false
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
  /v1/servicing/voice-provider/data/api/v1/twilio/initiate:
    post:
      tags:
        - Voice
      operationId: initiateVoiceProviderTestDial
      summary: Place a provider test dial
      description: Places a diagnostic provider test dial after checking the destination against the configured dial
        allowlist. This is not the governed collections dispatch path — outbound collections calls go through
        /v1/servicing/voice-dispatches — and a test dial never enters the contact-frequency ledger.
      x-permission: DIAL_SERVICING_VOICE_PROVIDER
      x-idempotent: true
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: Idempotency-Key
          in: header
          required: false
          description: Optional replay key for this logical mutation. Omission creates a fresh server-owned key for this attempt;
            blank, repeated, or longer-than-50-character values are rejected.
          schema:
            type: string
            minLength: 1
            maxLength: 50
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - call_id
                  - twilio_call_sid
                properties:
                  call_id:
                    type: string
                  twilio_call_sid:
                    type: string
              example:
                call_id: a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d
                twilio_call_sid: CA7c1f0b9e2d4a4f6e8a0b1c2d3e4f5a6b
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
        "409":
          $ref: "#/components/responses/Servicing409Error"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - to
                - workflow_id
              properties:
                to:
                  type: string
                workflow_id:
                  type: string
                borrower_name:
                  type: string
                borrower_zip:
                  type: string
                amount_due:
                  type: string
              example:
                to: "+15005550006"
                workflow_id: collections_demo_v2
                borrower_name: Jordan Sample
                borrower_zip: "78701"
                amount_due: "517.14"
            example:
              to: "+15005550006"
              workflow_id: collections_demo_v2
              borrower_name: Jordan Sample
              borrower_zip: "78701"
              amount_due: "517.14"
  /v1/servicing/voice-provider/data/api/v1/twilio/calls/{callId}/cancel:
    post:
      tags:
        - Voice
      operationId: cancelVoiceProviderCall
      summary: Cancel a provider test call
      description: Cancels an in-flight provider test call under the same dial permission. The request and the provider’s
        response pass through untouched.
      x-permission: DIAL_SERVICING_VOICE_PROVIDER
      x-idempotent: true
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: callId
          in: path
          required: true
          description: Stable opaque call identifier.
          schema:
            type: string
        - name: Idempotency-Key
          in: header
          required: false
          description: Optional replay key for this logical mutation. Omission creates a fresh server-owned key for this attempt;
            blank, repeated, or longer-than-50-character values are rejected.
          schema:
            type: string
            minLength: 1
            maxLength: 50
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - call_id
                  - state
                properties:
                  call_id:
                    type: string
                  state:
                    type: string
              example:
                call_id: a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d
                state: cancelled
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
        "409":
          $ref: "#/components/responses/Servicing409Error"
  /v1/servicing/cases/{caseId}/owner:
    put:
      tags:
        - Cases
      operationId: setCaseOwner
      summary: Assign or release the case owner
      description: Assigns, changes, or releases the case’s optional named owner; a null ownerWorkerId releases it. The case
        has no queue to move to, so this is the whole of reassigning a case, and allocation prefers the owner when
        routing its work.
      x-permission: UPDATE_SERVICING_CASE
      x-idempotent: true
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: caseId
          in: path
          required: true
          description: Positive numeric case identifier.
          schema:
            type: integer
            format: int64
            minimum: 1
        - name: Idempotency-Key
          in: header
          required: false
          description: Optional replay key for this logical mutation. Omission creates a fresh server-owned key for this attempt;
            blank, repeated, or longer-than-50-character values are rejected.
          schema:
            type: string
            minLength: 1
            maxLength: 50
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - caseId
                  - resourceId
                  - changes
                properties:
                  caseId:
                    type: integer
                    description: Stable opaque servicing case identifier.
                  resourceId:
                    type: integer
                  changes:
                    type: object
                    required:
                      - ownerWorkerId
                    properties:
                      ownerWorkerId:
                        type: integer
              example:
                caseId: 1001
                resourceId: 1001
                changes:
                  ownerWorkerId: 4101
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
        "409":
          $ref: "#/components/responses/Servicing409Error"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - reason
              properties:
                ownerWorkerId:
                  type: integer
                reason:
                  type: string
              example:
                ownerWorkerId: 4101
                reason: Maria is handling all contact with this customer.
            example:
              ownerWorkerId: 4101
              reason: Maria is handling all contact with this customer.
  /v1/servicing/cases/{caseId}/direct-service-decisions:
    post:
      tags:
        - Cases
      operationId: recordDirectServiceDecision
      summary: Record a direct-service decision
      description: Records a named person’s audited decision on a direct-service case, which the pinned workflow advances on
        in place of a system change. The result vocabulary is closed (NO_CHANGE_REQUIRED, CONFIRMATION_WAIVED,
        EXCEPTION_RAISED, the HOLD_* protection outcomes, and the HARDSHIP_* judgements) and the reason is mandatory.
      x-permission: UPDATE_SERVICING_CASE
      x-idempotent: true
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: caseId
          in: path
          required: true
          description: Positive numeric case identifier.
          schema:
            type: integer
            format: int64
            minimum: 1
        - name: Idempotency-Key
          in: header
          required: false
          description: Optional replay key for this logical mutation. Omission creates a fresh server-owned key for this attempt;
            blank, repeated, or longer-than-50-character values are rejected.
          schema:
            type: string
            minLength: 1
            maxLength: 50
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - caseId
                  - changes
                properties:
                  caseId:
                    type: integer
                    description: Stable opaque servicing case identifier.
                  changes:
                    type: object
                    required:
                      - decisionRecordId
                      - result
                    properties:
                      decisionRecordId:
                        type: integer
                      result:
                        type: string
              example:
                caseId: 1001
                changes:
                  decisionRecordId: 7601
                  result: NO_CHANGE_REQUIRED
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
        "409":
          $ref: "#/components/responses/Servicing409Error"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - result
                - reason
              properties:
                result:
                  type: string
                reason:
                  type: string
              example:
                result: NO_CHANGE_REQUIRED
                reason: Reviewed the account; the balance is already correct.
            example:
              result: NO_CHANGE_REQUIRED
              reason: Reviewed the account; the balance is already correct.
  /v1/servicing/tasks/{taskId}/decline:
    post:
      tags:
        - Tasks
      operationId: declineTask
      summary: Decline an offered task
      description: "Turns down a reserved offer so the task goes straight back to be offered to somebody else. Deliberately
        distinct from release: declining says nothing about the work. The optional declineReason must be one of BUSY,
        NOT_MY_SPECIALITY, STEPPING_AWAY, NEEDS_SOMEONE_ELSE, or OTHER."
      x-permission: DECLINE_SERVICING_TASK
      x-idempotent: true
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: taskId
          in: path
          required: true
          description: Positive numeric task identifier.
          schema:
            type: integer
            format: int64
            minimum: 1
        - name: Idempotency-Key
          in: header
          required: false
          description: Optional replay key for this logical mutation. Omission creates a fresh server-owned key for this attempt;
            blank, repeated, or longer-than-50-character values are rejected.
          schema:
            type: string
            minLength: 1
            maxLength: 50
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - taskId
                  - resourceId
                  - changes
                properties:
                  taskId:
                    type: integer
                  resourceId:
                    type: integer
                  changes:
                    type: object
                    required:
                      - status
                    properties:
                      status:
                        type: string
                        description: Current normalized lifecycle state.
              example:
                taskId: 2001
                resourceId: 2001
                changes:
                  status: AVAILABLE
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
        "409":
          $ref: "#/components/responses/Servicing409Error"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - declineReason
              properties:
                declineReason:
                  type: string
              example:
                declineReason: NOT_MY_SPECIALITY
            example:
              declineReason: NOT_MY_SPECIALITY
  /v1/servicing/me/events:
    get:
      tags:
        - Workforce
      operationId: streamWorkerEvents
      summary: Stream my worker events
      description: A server-sent-events stream (text/event-stream) that signals when the authenticated worker’s /me context
        changes. It only ever emits the servicing-me-changed event with an empty payload — /me stays the single source
        of the data — heartbeats every 25 seconds, closes itself after 15 minutes so credentials are re-presented, and
        returns 429 beyond four open streams per worker. The example shows one decoded stream event.
      x-permission: READ_SERVICING_TASK
      x-idempotent: false
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - event
                  - data
                properties:
                  event:
                    type: string
                  data:
                    type: object
                    required: []
                    properties: {}
              example:
                event: servicing-me-changed
                data: {}
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
  /v1/servicing/reports/promise-allocation:
    get:
      tags:
        - Servicing reports
      operationId: getPromiseAllocationReport
      summary: Read the promise and allocation scorecard
      description: "Scores promised callbacks against their windows and task offers against their reservations: kept, late,
        and missed counts with time-to-dial and time-to-accept percentiles, decline reasons, currently unassigned work,
        and queues holding open work that nobody present can take."
      x-permission: READ_SERVICING_REPORTS
      x-idempotent: false
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: windowDays
          in: query
          required: false
          description: Days of history the judged period covers; defaults to 30.
          schema:
            type: integer
            minimum: 1
            maximum: 90
            default: 30
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - asOf
                  - windowDays
                  - firstMinutesThreshold
                  - callbacks
                  - offers
                  - unassigned
                  - staffingGaps
                properties:
                  asOf:
                    type: string
                    format: date-time
                    description: Time at which the source says the fact was true.
                  windowDays:
                    type: integer
                  firstMinutesThreshold:
                    type: integer
                  callbacks:
                    type: object
                    required:
                      - promised
                      - onTime
                      - late
                      - missedUnresolved
                      - cancelledNoLongerNeeded
                      - cancelledOther
                      - dialledWithinWindowShare
                      - dialledFirstMinutesShare
                      - dialledFirstMinutes
                      - medianTimeToDialSeconds
                      - p90TimeToDialSeconds
                      - scheduledUpcoming
                      - inWindowNow
                      - atRiskNow
                      - cancellationReasons
                    properties:
                      promised:
                        type: integer
                      onTime:
                        type: integer
                      late:
                        type: integer
                      missedUnresolved:
                        type: integer
                      cancelledNoLongerNeeded:
                        type: integer
                      cancelledOther:
                        type: integer
                      dialledWithinWindowShare:
                        type: number
                      dialledFirstMinutesShare:
                        type: number
                      dialledFirstMinutes:
                        type: integer
                      medianTimeToDialSeconds:
                        type: integer
                      p90TimeToDialSeconds:
                        type: integer
                      scheduledUpcoming:
                        type: integer
                      inWindowNow:
                        type: integer
                      atRiskNow:
                        type: integer
                      cancellationReasons:
                        type: array
                        items:
                          type: object
                          required:
                            - reasonCode
                            - count
                          properties:
                            reasonCode:
                              type: string
                              description: Configured structured reason code.
                            count:
                              type: integer
                  offers:
                    type: object
                    required:
                      - total
                      - open
                      - accepted
                      - declined
                      - expired
                      - revoked
                      - acceptRate
                      - declineRate
                      - expiryRate
                      - medianTimeToAcceptSeconds
                      - p90TimeToAcceptSeconds
                      - medianTimeToReserveSeconds
                      - p90TimeToReserveSeconds
                      - declineReasons
                      - byQueue
                    properties:
                      total:
                        type: integer
                      open:
                        type: integer
                      accepted:
                        type: integer
                      declined:
                        type: integer
                      expired:
                        type: integer
                      revoked:
                        type: integer
                      acceptRate:
                        type: number
                      declineRate:
                        type: number
                      expiryRate:
                        type: number
                      medianTimeToAcceptSeconds:
                        type: integer
                      p90TimeToAcceptSeconds:
                        type: integer
                      medianTimeToReserveSeconds:
                        type: integer
                      p90TimeToReserveSeconds:
                        type: integer
                      declineReasons:
                        type: array
                        items:
                          type: object
                          required:
                            - reason
                            - count
                          properties:
                            reason:
                              type: string
                            count:
                              type: integer
                      byQueue:
                        type: array
                        items:
                          type: object
                          required:
                            - queueCode
                            - offers
                            - accepted
                            - declined
                            - expired
                          properties:
                            queueCode:
                              type: string
                            offers:
                              type: integer
                            accepted:
                              type: integer
                            declined:
                              type: integer
                            expired:
                              type: integer
                  unassigned:
                    type: object
                    required:
                      - availableWithoutOffer
                      - oldestAgeSeconds
                      - reasons
                    properties:
                      availableWithoutOffer:
                        type: integer
                      oldestAgeSeconds:
                        type: integer
                      reasons:
                        type: array
                        items:
                          type: object
                          required:
                            - reason
                            - count
                            - oldestAgeSeconds
                          properties:
                            reason:
                              type: string
                            count:
                              type: integer
                            oldestAgeSeconds:
                              type: integer
                  staffingGaps:
                    type: array
                    items:
                      type: object
                      required:
                        - queueCode
                        - openTasks
                        - memberCount
                        - availableMembers
                        - membersWithCapacity
                        - gap
                      properties:
                        queueCode:
                          type: string
                        openTasks:
                          type: integer
                        memberCount:
                          type: integer
                        availableMembers:
                          type: integer
                        membersWithCapacity:
                          type: integer
                        gap:
                          type: string
              example:
                asOf: 2026-07-25T18:40:00Z
                windowDays: 30
                firstMinutesThreshold: 10
                callbacks:
                  promised: 24
                  onTime: 18
                  late: 2
                  missedUnresolved: 1
                  cancelledNoLongerNeeded: 2
                  cancelledOther: 1
                  dialledWithinWindowShare: 0.857
                  dialledFirstMinutesShare: 0.667
                  dialledFirstMinutes: 14
                  medianTimeToDialSeconds: 312
                  p90TimeToDialSeconds: 1080
                  scheduledUpcoming: 5
                  inWindowNow: 1
                  atRiskNow: 0
                  cancellationReasons:
                    - reasonCode: PAYMENT_RECEIVED
                      count: 2
                offers:
                  total: 61
                  open: 2
                  accepted: 48
                  declined: 6
                  expired: 4
                  revoked: 1
                  acceptRate: 0.814
                  declineRate: 0.102
                  expiryRate: 0.068
                  medianTimeToAcceptSeconds: 41
                  p90TimeToAcceptSeconds: 138
                  medianTimeToReserveSeconds: 22
                  p90TimeToReserveSeconds: 95
                  declineReasons:
                    - reason: BUSY
                      count: 3
                  byQueue:
                    - queueCode: COLLECTIONS
                      offers: 61
                      accepted: 48
                      declined: 6
                      expired: 4
                unassigned:
                  availableWithoutOffer: 3
                  oldestAgeSeconds: 1860
                  reasons:
                    - reason: UNTRACKED
                      count: 3
                      oldestAgeSeconds: 1860
                staffingGaps:
                  - queueCode: HARDSHIP
                    openTasks: 4
                    memberCount: 0
                    availableMembers: 0
                    membersWithCapacity: 0
                    gap: NO_QUEUE_MEMBERS
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
  /v1/servicing/privacy-requests/{requestId}:
    get:
      tags:
        - Privacy requests
      operationId: getPrivacyRequest
      summary: Retrieve a privacy-rights request
      description: Returns one privacy-rights request projection with its statutory deadline, review-task state, terminal
        outcome reason when one exists, and the transitions allowed from its current status.
      x-permission: READ_SERVICING_PRIVACY_REQUEST
      x-idempotent: false
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: requestId
          in: path
          required: true
          description: Positive numeric request identifier.
          schema:
            type: integer
            format: int64
            minimum: 1
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - privacyRequestId
                  - externalRequestRef
                  - customerRef
                  - requestType
                  - regime
                  - summary
                  - status
                  - caseId
                  - externalCaseRef
                  - sourceInteractionId
                  - reviewTaskId
                  - reviewTaskAssignedWorkerId
                  - reviewTaskStatus
                  - receivedAt
                  - statutoryDueAt
                  - allowedTransitions
                properties:
                  privacyRequestId:
                    type: integer
                  externalRequestRef:
                    type: string
                  customerRef:
                    type: string
                  requestType:
                    type: string
                  regime:
                    type: string
                  summary:
                    type: string
                  status:
                    type: string
                    description: Current normalized lifecycle state.
                  caseId:
                    type: integer
                    description: Stable opaque servicing case identifier.
                  externalCaseRef:
                    type: string
                  sourceInteractionId:
                    type: integer
                  reviewTaskId:
                    type: integer
                  reviewTaskAssignedWorkerId:
                    type: integer
                  reviewTaskStatus:
                    type: string
                  receivedAt:
                    type: string
                    format: date-time
                  statutoryDueAt:
                    type: string
                    format: date-time
                  allowedTransitions:
                    type: array
                    items:
                      type: string
              example:
                privacyRequestId: 7501
                externalRequestRef: LE-PRIV-7501
                customerRef: "123"
                requestType: DELETION
                regime: CCPA_CPRA
                summary: Customer requests deletion of personal information.
                status: INTAKE
                caseId: 1001
                externalCaseRef: LE-CASE-1001
                sourceInteractionId: 3001
                reviewTaskId: 3302
                reviewTaskAssignedWorkerId: 4101
                reviewTaskStatus: ACCEPTED
                receivedAt: 2026-07-25T18:30:00Z
                statutoryDueAt: 2026-09-08T18:30:00Z
                allowedTransitions:
                  - IN_FULFILLMENT
                  - FULFILLED
                  - REJECTED
                  - REFERRED
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
  /v1/servicing/action-requests:
    get:
      tags:
        - Action requests
      operationId: listActionRequests
      summary: List action requests
      description: Lists materialized action requests across cases with the caller-specific allowed actions on each item; sort
        accepts createdAt, lastUpdatedAt, status, or actionType.
      x-permission: READ_SERVICING_ACTION_REQUEST
      x-idempotent: false
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: status
          in: query
          required: false
          description: Repeat to include multiple action-request states.
          schema:
            type: string
            enum:
              - PREPARED
              - APPROVAL_REQUIRED
              - APPROVED
              - REJECTED
              - SUBMITTED
              - PENDING_EXTERNAL
              - MANUAL_EXECUTION_REQUIRED
              - COMPLETED
              - FAILED
              - CANCELLED
        - name: actionType
          in: query
          required: false
          description: Repeat to include multiple registered action codes.
          schema:
            type: string
        - name: caseId
          in: query
          required: false
          description: Restrict to one case.
          schema:
            type: integer
        - name: limit
          in: query
          required: false
          description: Maximum rows to return; defaults to 50.
          schema:
            type: integer
            minimum: 1
            maximum: 200
            default: 50
        - name: offset
          in: query
          required: false
          description: Zero-based row offset; defaults to 0.
          schema:
            type: integer
            minimum: 0
            default: 0
        - name: sort
          in: query
          required: false
          description: Allowlisted sort field for this collection.
          schema:
            type: string
        - name: order
          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:
                  - items
                  - limit
                  - offset
                  - hasMore
                  - total
                properties:
                  items:
                    type: array
                    items:
                      type: object
                      required:
                        - actionRequestId
                        - externalActionRef
                        - caseId
                        - externalCaseRef
                        - customerRef
                        - actionType
                        - riskClass
                        - status
                        - preparedByActorType
                        - preparedByWorkerId
                        - approvalRequired
                        - approvalPermissionCode
                        - allowedActions
                        - createdAt
                        - lastUpdatedAt
                      properties:
                        actionRequestId:
                          type: integer
                          description: Stable opaque action-request identifier.
                        externalActionRef:
                          type: string
                        caseId:
                          type: integer
                          description: Stable opaque servicing case identifier.
                        externalCaseRef:
                          type: string
                        customerRef:
                          type: string
                        actionType:
                          type: string
                        riskClass:
                          type: string
                        status:
                          type: string
                          description: Current normalized lifecycle state.
                        preparedByActorType:
                          type: string
                        preparedByWorkerId:
                          type: integer
                        approvalRequired:
                          type: boolean
                        approvalPermissionCode:
                          type: string
                        allowedActions:
                          type: array
                          items:
                            type: string
                        createdAt:
                          type: string
                          format: date-time
                        lastUpdatedAt:
                          type: string
                          format: date-time
                  limit:
                    type: integer
                  offset:
                    type: integer
                  hasMore:
                    type: boolean
                  total:
                    type: integer
              example:
                items:
                  - actionRequestId: 6001
                    externalActionRef: LE-ACTION-6001
                    caseId: 1001
                    externalCaseRef: LE-CASE-1001
                    customerRef: "123"
                    actionType: AR_002
                    riskClass: R2
                    status: APPROVAL_REQUIRED
                    preparedByActorType: HUMAN
                    preparedByWorkerId: 4101
                    approvalRequired: true
                    approvalPermissionCode: APPROVE_SERVICING_PROMISE
                    allowedActions:
                      - APPROVE
                      - REJECT
                    createdAt: 2026-07-25T18:30:00Z
                    lastUpdatedAt: 2026-07-25T18:30:00Z
                limit: 50
                offset: 0
                hasMore: false
                total: 1
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
  /v1/servicing/reconciliation-drift/{driftId}:
    get:
      tags:
        - Servicing reports
      operationId: getReconciliationDriftWorkspace
      summary: Retrieve a reconciliation-drift workspace
      description: "Returns one drift item as a reviewer workspace: the expected-versus-actual comparison, the lending-core
        event lane it came from when one exists, the resolution record, and exactly the resolution actions this drift
        currently permits. The drift list stays on the reconciliation report."
      x-permission: READ_SERVICING_RECONCILIATION_DRIFT
      x-idempotent: false
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: driftId
          in: path
          required: true
          description: Stable opaque drift identifier.
          schema:
            type: string
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - driftId
                  - driftType
                  - objectType
                  - objectRef
                  - customerRef
                  - loanRef
                  - detail
                  - status
                  - priority
                  - externalCaseRef
                  - caseId
                  - reviewTaskId
                  - detectedAt
                  - comparison
                  - lane
                  - resolution
                  - availableActions
                properties:
                  driftId:
                    type: integer
                  driftType:
                    type: string
                  objectType:
                    type: string
                  objectRef:
                    type: string
                  customerRef:
                    type: string
                  loanRef:
                    type: string
                  detail:
                    type: string
                  status:
                    type: string
                    description: Current normalized lifecycle state.
                  priority:
                    type: string
                  externalCaseRef:
                    type: string
                  caseId:
                    type: integer
                    description: Stable opaque servicing case identifier.
                  reviewTaskId:
                    type: integer
                  detectedAt:
                    type: string
                    format: date-time
                  comparison:
                    type: object
                    required:
                      - expected
                      - actual
                      - failure
                    properties:
                      expected:
                        type: string
                      actual:
                        type: string
                      failure:
                        type: string
                  lane:
                    type: object
                    required:
                      - signalEventId
                      - aggregateType
                      - aggregateRef
                      - sequenceNo
                      - shard
                      - processingStatus
                      - lastError
                      - attempts
                      - laneStatus
                      - laneHighWater
                    properties:
                      signalEventId:
                        type: integer
                      aggregateType:
                        type: string
                      aggregateRef:
                        type: string
                      sequenceNo:
                        type: integer
                      shard:
                        type: integer
                      processingStatus:
                        type: string
                      lastError:
                        type: string
                      attempts:
                        type: integer
                      laneStatus:
                        type: string
                      laneHighWater:
                        type: integer
                  resolution:
                    type: object
                    required: []
                    properties: {}
                  availableActions:
                    type: array
                    items:
                      type: object
                      required:
                        - action
                        - displayName
                        - description
                        - available
                      properties:
                        action:
                          type: string
                        displayName:
                          type: string
                        description:
                          type: string
                        available:
                          type: boolean
              example:
                driftId: 81
                driftType: EXPECTED_STATE_MISMATCH
                objectType: AUTOPAY
                objectRef: "456"
                customerRef: "123"
                loanRef: "456"
                detail: The LMS reports autopay active; servicing expected it suspended.
                status: OPEN
                priority: HIGH
                externalCaseRef: LE-CASE-1001
                caseId: 1001
                reviewTaskId: 2005
                detectedAt: 2026-07-25T18:30:00Z
                comparison:
                  expected: AUTOPAY_SUSPENDED
                  actual: AUTOPAY_ACTIVE
                  failure: The downstream update was rejected.
                lane:
                  signalEventId: 5501
                  aggregateType: LOAN
                  aggregateRef: "456"
                  sequenceNo: 118
                  shard: 3
                  processingStatus: FAILED
                  lastError: Autopay suspension rejected by the LMS.
                  attempts: 3
                  laneStatus: POISONED
                  laneHighWater: 117
                resolution: {}
                availableActions:
                  - action: RETRY
                    displayName: Re-drive the failed event
                    description: Clears the poisoned lane and replays the event through the ordinary poller.
                    available: true
                  - action: MANUAL_REPAIR
                    displayName: Record a repair made through a governed path
                    description: Requires a governed command or an action request on the linked case to point at.
                    available: true
                  - action: CANCEL_DEPENDENT_WORK
                    displayName: Cancel the work that depended on this
                    description: Cancels the case work this drift blocked, with an audited reason on each item.
                    available: true
                  - action: ACCEPT_AS_EXPECTED
                    displayName: Accept the difference as correct
                    description: Records that the two sides are allowed to differ here, and why.
                    available: true
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
  /v1/servicing/reconciliation-drift/{driftId}/resolve:
    post:
      tags:
        - Servicing reports
      operationId: resolveReconciliationDrift
      summary: Resolve a reconciliation drift
      description: Runs one permitted resolution action — RETRY, MANUAL_REPAIR, CANCEL_DEPENDENT_WORK, or ACCEPT_AS_EXPECTED —
        and, when it succeeds, resolves the drift and completes its review task in the same transaction. A stated cause
        and follow-up statement are required whatever the action; MANUAL_REPAIR points at the governed change via
        repairReference, and ACCEPT_AS_EXPECTED resolves as ACCEPTED.
      x-permission: RESOLVE_SERVICING_RECONCILIATION_DRIFT
      x-idempotent: true
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: driftId
          in: path
          required: true
          description: Stable opaque drift identifier.
          schema:
            type: string
        - name: Idempotency-Key
          in: header
          required: false
          description: Optional replay key for this logical mutation. Omission creates a fresh server-owned key for this attempt;
            blank, repeated, or longer-than-50-character values are rejected.
          schema:
            type: string
            minLength: 1
            maxLength: 50
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - driftId
                  - resourceId
                  - changes
                properties:
                  driftId:
                    type: integer
                  resourceId:
                    type: integer
                  changes:
                    type: object
                    required:
                      - status
                      - action
                      - evidenceRef
                    properties:
                      status:
                        type: string
                        description: Current normalized lifecycle state.
                      action:
                        type: string
                      evidenceRef:
                        type: string
              example:
                driftId: 81
                resourceId: 81
                changes:
                  status: RESOLVED
                  action: RETRY
                  evidenceRef: signal:5501 status:PROCESSED processed:true
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
        "409":
          $ref: "#/components/responses/Servicing409Error"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - action
                - cause
                - followUpWork
              properties:
                action:
                  type: string
                cause:
                  type: string
                followUpWork:
                  type: string
              example:
                action: RETRY
                cause: The LMS rejected the update during its maintenance window.
                followUpWork: None; the replayed event applied cleanly.
            example:
              action: RETRY
              cause: The LMS rejected the update during its maintenance window.
              followUpWork: None; the replayed event applied cleanly.
  /v1/servicing/admin/hardship-policies:
    get:
      tags:
        - Hardship
      operationId: listHardshipPolicies
      summary: List the hardship policy portfolio
      description: Returns the active common guardrails, one card per hardship program with its executable state and
        active-version summary, and whether the portfolio as a whole is coherent.
      x-permission: READ_SERVICING_HARDSHIP_POLICY
      x-idempotent: false
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - commonGuardrails
                  - programs
                  - portfolioValid
                properties:
                  commonGuardrails:
                    type: object
                    required:
                      - version
                      - activatedAt
                      - guardrails
                    properties:
                      version:
                        type: integer
                        description: Monotonically increasing resource version.
                      activatedAt:
                        type: string
                        format: date-time
                      guardrails:
                        type: object
                        required:
                          - guardrailVersion
                          - minimumLoanAgeInstallments
                          - maximumActiveHardshipCasesPerLoan
                          - requireVerifiedContactForOffer
                          - requireWorkflowConfirmedEvidence
                          - prohibitPrincipalForgiveness
                          - prohibitRateChange
                          - specialistConditions
                          - offerValidityHoursMaximum
                          - documentDeadlineHoursMaximum
                          - maximumDeferredPayments
                          - reevaluateOnMaterialLoanDrift
                        properties:
                          guardrailVersion:
                            type: integer
                          minimumLoanAgeInstallments:
                            type: integer
                          maximumActiveHardshipCasesPerLoan:
                            type: integer
                          requireVerifiedContactForOffer:
                            type: boolean
                          requireWorkflowConfirmedEvidence:
                            type: boolean
                          prohibitPrincipalForgiveness:
                            type: boolean
                          prohibitRateChange:
                            type: boolean
                          specialistConditions:
                            type: array
                            items:
                              type: string
                          offerValidityHoursMaximum:
                            type: integer
                          documentDeadlineHoursMaximum:
                            type: integer
                          maximumDeferredPayments:
                            type: integer
                          reevaluateOnMaterialLoanDrift:
                            type: boolean
                  programs:
                    type: array
                    items:
                      type: object
                      required:
                        - programCode
                        - displayName
                        - hardshipReasonCode
                        - description
                        - state
                        - activeVersion
                        - effectiveFrom
                        - effectiveTo
                        - summary
                        - versionCount
                      properties:
                        programCode:
                          type: string
                        displayName:
                          type: string
                        hardshipReasonCode:
                          type: string
                        description:
                          type: string
                        state:
                          type: string
                        activeVersion:
                          type: integer
                        effectiveFrom:
                          type: string
                        effectiveTo:
                          type: string
                        summary:
                          type: object
                          required:
                            - reliefType
                            - straightThroughMaximum
                            - humanApprovalMaximum
                            - humanApprovalPermission
                            - requiredEvidenceCode
                            - offerValidityHours
                            - ruleCount
                            - scope
                            - workflow
                          properties:
                            reliefType:
                              type: string
                            straightThroughMaximum:
                              type: integer
                            humanApprovalMaximum:
                              type: integer
                            humanApprovalPermission:
                              type: string
                            requiredEvidenceCode:
                              type: string
                            offerValidityHours:
                              type: integer
                            ruleCount:
                              type: integer
                            scope:
                              type: object
                              required:
                                - productClasses
                                - jurisdictions
                                - currencies
                                - repaymentFrequencies
                                - requiredNativeCapability
                              properties:
                                productClasses:
                                  type: array
                                  items:
                                    type: string
                                jurisdictions:
                                  type: array
                                  items:
                                    type: string
                                currencies:
                                  type: array
                                  items:
                                    type: string
                                repaymentFrequencies:
                                  type: array
                                  items:
                                    type: string
                                requiredNativeCapability:
                                  type: string
                            workflow:
                              type: object
                              required:
                                - caseType
                                - workflowKey
                              properties:
                                caseType:
                                  type: string
                                workflowKey:
                                  type: string
                        versionCount:
                          type: integer
                  portfolioValid:
                    type: boolean
              example:
                commonGuardrails:
                  version: 2
                  activatedAt: 2026-07-01T09:00:00Z
                  guardrails:
                    guardrailVersion: 2
                    minimumLoanAgeInstallments: 1
                    maximumActiveHardshipCasesPerLoan: 1
                    requireVerifiedContactForOffer: true
                    requireWorkflowConfirmedEvidence: true
                    prohibitPrincipalForgiveness: true
                    prohibitRateChange: true
                    specialistConditions:
                      - BANKRUPTCY
                      - LITIGATION
                      - FRAUD_INVESTIGATION
                      - DECEASED
                      - LEGAL_HOLD
                      - RECOVERY_PLACEMENT
                    offerValidityHoursMaximum: 168
                    documentDeadlineHoursMaximum: 504
                    maximumDeferredPayments: 6
                    reevaluateOnMaterialLoanDrift: true
                programs:
                  - programCode: MEDICAL_LEAVE_DEFERRAL_V1
                    displayName: Medical Leave Deferral
                    hardshipReasonCode: MEDICAL_LEAVE
                    description: Defers the loan-repayment portion of scheduled payments to maturity during documented temporary medical
                      leave.
                    state: ACTIVE
                    activeVersion: 1
                    effectiveFrom: 2026-01-01
                    effectiveTo: null
                    summary:
                      reliefType: DEFER_SCHEDULED_INSTALLMENTS_TO_MATURITY
                      straightThroughMaximum: 3
                      humanApprovalMaximum: 6
                      humanApprovalPermission: APPROVE_SERVICING_HARDSHIP_DEFERRAL_UP_TO_6
                      requiredEvidenceCode: DOCTORS_MEDICAL_LEAVE_CERTIFICATE
                      offerValidityHours: 168
                      ruleCount: 8
                      scope:
                        productClasses:
                          - COVERED_CONSUMER
                        jurisdictions:
                          - US
                        currencies:
                          - USD
                        repaymentFrequencies:
                          - MONTHLY
                        requiredNativeCapability: DEFER_SCHEDULED_INSTALLMENTS_TO_MATURITY
                      workflow:
                        caseType: HARDSHIP_ASSISTANCE
                        workflowKey: MEDICAL_LEAVE_HARDSHIP_V1
                    versionCount: 2
                portfolioValid: true
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
  /v1/servicing/admin/hardship-policies/{programCode}:
    get:
      tags:
        - Hardship
      operationId: getHardshipPolicyProgram
      summary: Retrieve a hardship program
      description: Returns one program with the active common guardrails, every version with its lifecycle timestamps and
        validation verdict, and the program audit trail.
      x-permission: READ_SERVICING_HARDSHIP_POLICY
      x-idempotent: false
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: programCode
          in: path
          required: true
          description: Stable opaque programCode identifier.
          schema:
            type: string
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - programCode
                  - displayName
                  - hardshipReasonCode
                  - description
                  - commonGuardrails
                  - versions
                  - audit
                properties:
                  programCode:
                    type: string
                  displayName:
                    type: string
                  hardshipReasonCode:
                    type: string
                  description:
                    type: string
                  commonGuardrails:
                    type: object
                    required:
                      - version
                      - activatedAt
                      - guardrails
                    properties:
                      version:
                        type: integer
                        description: Monotonically increasing resource version.
                      activatedAt:
                        type: string
                        format: date-time
                      guardrails:
                        type: object
                        required:
                          - guardrailVersion
                          - minimumLoanAgeInstallments
                          - maximumActiveHardshipCasesPerLoan
                          - requireVerifiedContactForOffer
                          - requireWorkflowConfirmedEvidence
                          - prohibitPrincipalForgiveness
                          - prohibitRateChange
                          - specialistConditions
                          - offerValidityHoursMaximum
                          - documentDeadlineHoursMaximum
                          - maximumDeferredPayments
                          - reevaluateOnMaterialLoanDrift
                        properties:
                          guardrailVersion:
                            type: integer
                          minimumLoanAgeInstallments:
                            type: integer
                          maximumActiveHardshipCasesPerLoan:
                            type: integer
                          requireVerifiedContactForOffer:
                            type: boolean
                          requireWorkflowConfirmedEvidence:
                            type: boolean
                          prohibitPrincipalForgiveness:
                            type: boolean
                          prohibitRateChange:
                            type: boolean
                          specialistConditions:
                            type: array
                            items:
                              type: string
                          offerValidityHoursMaximum:
                            type: integer
                          documentDeadlineHoursMaximum:
                            type: integer
                          maximumDeferredPayments:
                            type: integer
                          reevaluateOnMaterialLoanDrift:
                            type: boolean
                  versions:
                    type: array
                    items:
                      type: object
                      required:
                        - versionId
                        - version
                        - status
                        - definitionDigest
                        - effectiveFrom
                        - effectiveTo
                        - reason
                        - createdAt
                        - validatedAt
                        - activatedAt
                        - retiredAt
                        - expectedVersion
                        - simulationCount
                        - validation
                      properties:
                        versionId:
                          type: integer
                        version:
                          type: integer
                          description: Monotonically increasing resource version.
                        status:
                          type: string
                          description: Current normalized lifecycle state.
                        definitionDigest:
                          type: string
                        effectiveFrom:
                          type: string
                        effectiveTo:
                          type: string
                        reason:
                          type: string
                        createdAt:
                          type: string
                          format: date-time
                        validatedAt:
                          type: string
                          format: date-time
                        activatedAt:
                          type: string
                          format: date-time
                        retiredAt:
                          type: string
                          format: date-time
                        expectedVersion:
                          type: integer
                        simulationCount:
                          type: integer
                        validation:
                          type: object
                          required:
                            - valid
                            - findings
                          properties:
                            valid:
                              type: boolean
                            findings:
                              type: array
                              items:
                                type: object
                  audit:
                    type: array
                    items:
                      type: object
                      required:
                        - version
                        - operation
                        - outcome
                        - reason
                        - actorType
                        - actorRef
                        - occurredAt
                      properties:
                        version:
                          type: integer
                          description: Monotonically increasing resource version.
                        operation:
                          type: string
                        outcome:
                          type: string
                        reason:
                          type: string
                        actorType:
                          type: string
                        actorRef:
                          type: string
                        occurredAt:
                          type: string
                          format: date-time
              example:
                programCode: MEDICAL_LEAVE_DEFERRAL_V1
                displayName: Medical Leave Deferral
                hardshipReasonCode: MEDICAL_LEAVE
                description: Defers the loan-repayment portion of scheduled payments to maturity during documented temporary medical
                  leave.
                commonGuardrails:
                  version: 2
                  activatedAt: 2026-07-01T09:00:00Z
                  guardrails:
                    guardrailVersion: 2
                    minimumLoanAgeInstallments: 1
                    maximumActiveHardshipCasesPerLoan: 1
                    requireVerifiedContactForOffer: true
                    requireWorkflowConfirmedEvidence: true
                    prohibitPrincipalForgiveness: true
                    prohibitRateChange: true
                    specialistConditions:
                      - BANKRUPTCY
                      - LITIGATION
                      - FRAUD_INVESTIGATION
                      - DECEASED
                      - LEGAL_HOLD
                      - RECOVERY_PLACEMENT
                    offerValidityHoursMaximum: 168
                    documentDeadlineHoursMaximum: 504
                    maximumDeferredPayments: 6
                    reevaluateOnMaterialLoanDrift: true
                versions:
                  - versionId: 9302
                    version: 2
                    status: VALIDATED
                    definitionDigest: 8c1f6a2d9b304e57
                    effectiveFrom: null
                    effectiveTo: null
                    reason: Extends the arrears eligibility rule from 90 to 120 days overdue.
                    createdAt: 2026-07-20T10:00:00Z
                    validatedAt: 2026-07-21T09:30:00Z
                    activatedAt: null
                    retiredAt: null
                    expectedVersion: 2
                    simulationCount: 1
                    validation:
                      valid: true
                      findings: []
                  - versionId: 9301
                    version: 1
                    status: ACTIVE
                    definitionDigest: 5d20c7e1a94f6b83
                    effectiveFrom: 2026-01-01
                    effectiveTo: null
                    reason: Seeded lender-approved medical-leave deferral policy.
                    createdAt: 2026-01-01T00:00:00Z
                    validatedAt: 2026-01-01T00:00:00Z
                    activatedAt: 2026-01-01T00:00:00Z
                    retiredAt: null
                    expectedVersion: 1
                    simulationCount: 2
                audit:
                  - version: 2
                    operation: VALIDATE
                    outcome: ACCEPTED
                    reason: The version validates
                    actorType: HUMAN
                    actorRef: "4101"
                    occurredAt: 2026-07-21T09:30:00Z
                  - version: 2
                    operation: DRAFT
                    outcome: ACCEPTED
                    reason: Extends the arrears eligibility rule from 90 to 120 days overdue.
                    actorType: HUMAN
                    actorRef: "4101"
                    occurredAt: 2026-07-20T10:00:00Z
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
  /v1/servicing/admin/hardship-policies/{programCode}/versions/{version}:
    get:
      tags:
        - Hardship
      operationId: getHardshipPolicyVersion
      summary: Retrieve one policy version
      description: Returns one version with its complete definition, the guardrail version it was drafted under, its
        validation verdict, and its most recent synthetic simulations.
      x-permission: READ_SERVICING_HARDSHIP_POLICY
      x-idempotent: false
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: programCode
          in: path
          required: true
          description: Stable opaque programCode identifier.
          schema:
            type: string
        - name: version
          in: path
          required: true
          description: Monotonically increasing resource version.
          schema:
            type: string
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - programCode
                  - versionId
                  - version
                  - status
                  - definitionDigest
                  - effectiveFrom
                  - effectiveTo
                  - reason
                  - createdAt
                  - validatedAt
                  - activatedAt
                  - retiredAt
                  - expectedVersion
                  - guardrailVersion
                  - definition
                  - validation
                  - simulations
                properties:
                  programCode:
                    type: string
                  versionId:
                    type: integer
                  version:
                    type: integer
                    description: Monotonically increasing resource version.
                  status:
                    type: string
                    description: Current normalized lifecycle state.
                  definitionDigest:
                    type: string
                  effectiveFrom:
                    type: string
                  effectiveTo:
                    type: string
                  reason:
                    type: string
                  createdAt:
                    type: string
                    format: date-time
                  validatedAt:
                    type: string
                    format: date-time
                  activatedAt:
                    type: string
                    format: date-time
                  retiredAt:
                    type: string
                    format: date-time
                  expectedVersion:
                    type: integer
                  guardrailVersion:
                    type: integer
                  definition:
                    type: object
                    required:
                      - programCode
                      - displayName
                      - hardshipReasonCode
                      - scope
                      - evidence
                      - rules
                      - authority
                      - terms
                      - communication
                      - workflow
                    properties:
                      programCode:
                        type: string
                      displayName:
                        type: string
                      hardshipReasonCode:
                        type: string
                      scope:
                        type: object
                        required:
                          - productClasses
                          - jurisdictions
                          - currencies
                          - repaymentFrequencies
                          - requiredNativeCapability
                        properties:
                          productClasses:
                            type: array
                            items:
                              type: string
                          jurisdictions:
                            type: array
                            items:
                              type: string
                          currencies:
                            type: array
                            items:
                              type: string
                          repaymentFrequencies:
                            type: array
                            items:
                              type: string
                          requiredNativeCapability:
                            type: string
                      evidence:
                        type: object
                        required:
                          - requiredEvidenceCode
                          - acceptedScreeningResults
                          - humanConfirmationAccepted
                        properties:
                          requiredEvidenceCode:
                            type: string
                          acceptedScreeningResults:
                            type: array
                            items:
                              type: string
                          humanConfirmationAccepted:
                            type: boolean
                      rules:
                        type: array
                        items:
                          type: object
                          required:
                            - key
                            - fact
                            - operator
                            - value
                            - onFail
                            - onMissing
                            - operatorExplanation
                            - borrowerSafeReason
                          properties:
                            key:
                              type: string
                            fact:
                              type: string
                            operator:
                              type: string
                            value:
                              type: string
                            onFail:
                              type: string
                            onMissing:
                              type: string
                            operatorExplanation:
                              type: string
                            borrowerSafeReason:
                              type: string
                      authority:
                        type: object
                        required:
                          - straightThroughMaximum
                          - humanApprovalMaximum
                          - humanApprovalPermission
                          - outsideProgramAbove
                        properties:
                          straightThroughMaximum:
                            type: integer
                          humanApprovalMaximum:
                            type: integer
                          humanApprovalPermission:
                            type: string
                          outsideProgramAbove:
                            type: integer
                      terms:
                        type: object
                        required:
                          - reliefType
                          - minimumDeferredPayments
                          - maximumDeferredPayments
                          - principalForgiveness
                          - rateChange
                        properties:
                          reliefType:
                            type: string
                          minimumDeferredPayments:
                            type: integer
                          maximumDeferredPayments:
                            type: integer
                          principalForgiveness:
                            type: boolean
                          rateChange:
                            type: boolean
                      communication:
                        type: object
                        required:
                          - agreementTemplateCode
                          - invitationTemplateCode
                          - replacementTemplateCode
                          - reminderTemplateCode
                          - ineligibilityTemplateCode
                          - language
                          - offerValidityHours
                          - documentDeadlineHours
                          - reminderAfterHours
                        properties:
                          agreementTemplateCode:
                            type: string
                          invitationTemplateCode:
                            type: string
                          replacementTemplateCode:
                            type: string
                          reminderTemplateCode:
                            type: string
                          ineligibilityTemplateCode:
                            type: string
                          language:
                            type: string
                          offerValidityHours:
                            type: integer
                          documentDeadlineHours:
                            type: integer
                          reminderAfterHours:
                            type: integer
                      workflow:
                        type: object
                        required:
                          - caseType
                          - workflowKey
                        properties:
                          caseType:
                            type: string
                          workflowKey:
                            type: string
                  validation:
                    type: object
                    required:
                      - valid
                      - findings
                    properties:
                      valid:
                        type: boolean
                      findings:
                        type: array
                        items:
                          type: object
                  simulations:
                    type: array
                    items:
                      type: object
                      required:
                        - simulationId
                        - resultCode
                        - runAt
                        - synthetic
                        - input
                        - result
                      properties:
                        simulationId:
                          type: integer
                        resultCode:
                          type: string
                        runAt:
                          type: string
                          format: date-time
                        synthetic:
                          type: boolean
                        input:
                          type: object
                          required:
                            - requestedCount
                            - facts
                          properties:
                            requestedCount:
                              type: integer
                            facts:
                              type: object
                              required:
                                - employmentActive
                                - certificateState
                                - leaveStartDate
                                - expectedReturnDate
                                - canResumeAfterReturn
                                - loanStatus
                                - daysOverdue
                              properties:
                                employmentActive:
                                  type: string
                                certificateState:
                                  type: string
                                leaveStartDate:
                                  type: string
                                  format: date
                                expectedReturnDate:
                                  type: string
                                  format: date
                                canResumeAfterReturn:
                                  type: string
                                loanStatus:
                                  type: string
                                daysOverdue:
                                  type: string
                        result:
                          type: object
                          required:
                            - result
                            - requestedCount
                            - allowedCount
                            - requiredPermission
                            - reasonCodes
                            - ruleTrace
                            - synthetic
                          properties:
                            result:
                              type: string
                            requestedCount:
                              type: integer
                            allowedCount:
                              type: integer
                            requiredPermission:
                              type: string
                            reasonCodes:
                              type: array
                              items:
                                type: object
                            ruleTrace:
                              type: array
                              items:
                                type: object
                                required:
                                  - key
                                  - fact
                                  - operator
                                  - expected
                                  - observed
                                  - status
                                  - operatorExplanation
                                properties:
                                  key:
                                    type: string
                                  fact:
                                    type: string
                                  operator:
                                    type: string
                                  expected:
                                    type: string
                                  observed:
                                    type: string
                                  status:
                                    type: string
                                    description: Current normalized lifecycle state.
                                  operatorExplanation:
                                    type: string
                            synthetic:
                              type: boolean
              example:
                programCode: MEDICAL_LEAVE_DEFERRAL_V1
                versionId: 9302
                version: 2
                status: VALIDATED
                definitionDigest: 8c1f6a2d9b304e57
                effectiveFrom: null
                effectiveTo: null
                reason: Extends the arrears eligibility rule from 90 to 120 days overdue.
                createdAt: 2026-07-20T10:00:00Z
                validatedAt: 2026-07-21T09:30:00Z
                activatedAt: null
                retiredAt: null
                expectedVersion: 2
                guardrailVersion: 2
                definition:
                  programCode: MEDICAL_LEAVE_DEFERRAL_V1
                  displayName: Medical Leave Deferral
                  hardshipReasonCode: MEDICAL_LEAVE
                  scope:
                    productClasses:
                      - COVERED_CONSUMER
                    jurisdictions:
                      - US
                    currencies:
                      - USD
                    repaymentFrequencies:
                      - MONTHLY
                    requiredNativeCapability: DEFER_SCHEDULED_INSTALLMENTS_TO_MATURITY
                  evidence:
                    requiredEvidenceCode: DOCTORS_MEDICAL_LEAVE_CERTIFICATE
                    acceptedScreeningResults:
                      - SCREENING_PASSED
                      - VERIFIED
                    humanConfirmationAccepted: true
                  rules:
                    - key: EMPLOYMENT_ACTIVE
                      fact: employmentActive
                      operator: EQ
                      value: "true"
                      onFail: INELIGIBLE
                      onMissing: MISSING_INFORMATION
                      operatorExplanation: The borrower must still be employed; this program defers payments during leave, it does not address
                        job loss.
                      borrowerSafeReason: EMPLOYMENT_NOT_ACTIVE
                    - key: LEAVE_DOCUMENTED
                      fact: certificateState
                      operator: EQ
                      value: COMPLETE
                      onFail: MISSING_INFORMATION
                      onMissing: MISSING_INFORMATION
                      operatorExplanation: The workflow must have confirmed a complete doctor certificate before eligibility is evaluated.
                      borrowerSafeReason: EVIDENCE_INCOMPLETE
                    - key: DELINQUENCY_WITHIN_GUARDRAIL
                      fact: daysOverdue
                      operator: LTE
                      value: "120"
                      onFail: INELIGIBLE
                      onMissing: PASS
                      operatorExplanation: Beyond the lender-configured arrears age this program is not the right instrument.
                      borrowerSafeReason: ARREARS_TOO_OLD
                  authority:
                    straightThroughMaximum: 3
                    humanApprovalMaximum: 6
                    humanApprovalPermission: APPROVE_SERVICING_HARDSHIP_DEFERRAL_UP_TO_6
                    outsideProgramAbove: 6
                  terms:
                    reliefType: DEFER_SCHEDULED_INSTALLMENTS_TO_MATURITY
                    minimumDeferredPayments: 1
                    maximumDeferredPayments: 6
                    principalForgiveness: false
                    rateChange: false
                  communication:
                    agreementTemplateCode: HARDSHIP_MEDICAL_LEAVE_AGREEMENT
                    invitationTemplateCode: HARDSHIP_CERTIFICATE_REQUEST
                    replacementTemplateCode: HARDSHIP_CERTIFICATE_REPLACEMENT
                    reminderTemplateCode: HARDSHIP_CERTIFICATE_REMINDER
                    ineligibilityTemplateCode: HARDSHIP_NOT_ELIGIBLE
                    language: en
                    offerValidityHours: 168
                    documentDeadlineHours: 168
                    reminderAfterHours: 72
                  workflow:
                    caseType: HARDSHIP_ASSISTANCE
                    workflowKey: MEDICAL_LEAVE_HARDSHIP_V1
                validation:
                  valid: true
                  findings: []
                simulations:
                  - simulationId: 8801
                    resultCode: HUMAN_APPROVAL_REQUIRED
                    runAt: 2026-07-21T09:35:00Z
                    synthetic: true
                    input:
                      requestedCount: 4
                      facts:
                        employmentActive: "true"
                        certificateState: COMPLETE
                        leaveStartDate: 2026-07-14
                        expectedReturnDate: 2026-08-25
                        canResumeAfterReturn: "true"
                        loanStatus: ACTIVE
                        daysOverdue: "0"
                    result:
                      result: HUMAN_APPROVAL_REQUIRED
                      requestedCount: 4
                      allowedCount: 4
                      requiredPermission: APPROVE_SERVICING_HARDSHIP_DEFERRAL_UP_TO_6
                      reasonCodes: []
                      ruleTrace:
                        - key: EMPLOYMENT_ACTIVE
                          fact: employmentActive
                          operator: EQ
                          expected: "true"
                          observed: "true"
                          status: PASS
                          operatorExplanation: The borrower must still be employed; this program defers payments during leave, it does not address
                            job loss.
                      synthetic: true
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
  /v1/servicing/admin/hardship-policies/{programCode}/versions:
    post:
      tags:
        - Hardship
      operationId: draftHardshipPolicyVersion
      summary: Draft the next policy version
      description: Creates the next immutable draft version of a program from a complete definition. The definition is parsed
        strictly on write; an unrunnable definition is refused here rather than stored.
      x-permission: ADMIN_SERVICING_HARDSHIP_POLICY
      x-idempotent: true
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: programCode
          in: path
          required: true
          description: Stable opaque programCode identifier.
          schema:
            type: string
        - name: Idempotency-Key
          in: header
          required: false
          description: Optional replay key for this logical mutation. Omission creates a fresh server-owned key for this attempt;
            blank, repeated, or longer-than-50-character values are rejected.
          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:
                      - programVersionId
                      - operation
                    properties:
                      programVersionId:
                        type: integer
                      operation:
                        type: string
              example:
                resourceId: 9302
                changes:
                  programVersionId: 9302
                  operation: DRAFT
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
        "409":
          $ref: "#/components/responses/Servicing409Error"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - definition
                - reason
              properties:
                definition:
                  type: object
                  required:
                    - programCode
                    - displayName
                    - hardshipReasonCode
                    - scope
                    - evidence
                    - rules
                    - authority
                    - terms
                    - communication
                    - workflow
                  properties:
                    programCode:
                      type: string
                    displayName:
                      type: string
                    hardshipReasonCode:
                      type: string
                    scope:
                      type: object
                      required:
                        - productClasses
                        - jurisdictions
                        - currencies
                        - repaymentFrequencies
                        - requiredNativeCapability
                      properties:
                        productClasses:
                          type: array
                          items:
                            type: string
                        jurisdictions:
                          type: array
                          items:
                            type: string
                        currencies:
                          type: array
                          items:
                            type: string
                        repaymentFrequencies:
                          type: array
                          items:
                            type: string
                        requiredNativeCapability:
                          type: string
                    evidence:
                      type: object
                      required:
                        - requiredEvidenceCode
                        - acceptedScreeningResults
                        - humanConfirmationAccepted
                      properties:
                        requiredEvidenceCode:
                          type: string
                        acceptedScreeningResults:
                          type: array
                          items:
                            type: string
                        humanConfirmationAccepted:
                          type: boolean
                    rules:
                      type: array
                      items:
                        type: object
                        required:
                          - key
                          - fact
                          - operator
                          - value
                          - onFail
                          - onMissing
                          - operatorExplanation
                          - borrowerSafeReason
                        properties:
                          key:
                            type: string
                          fact:
                            type: string
                          operator:
                            type: string
                          value:
                            type: string
                          onFail:
                            type: string
                          onMissing:
                            type: string
                          operatorExplanation:
                            type: string
                          borrowerSafeReason:
                            type: string
                    authority:
                      type: object
                      required:
                        - straightThroughMaximum
                        - humanApprovalMaximum
                        - humanApprovalPermission
                        - outsideProgramAbove
                      properties:
                        straightThroughMaximum:
                          type: integer
                        humanApprovalMaximum:
                          type: integer
                        humanApprovalPermission:
                          type: string
                        outsideProgramAbove:
                          type: integer
                    terms:
                      type: object
                      required:
                        - reliefType
                        - minimumDeferredPayments
                        - maximumDeferredPayments
                        - principalForgiveness
                        - rateChange
                      properties:
                        reliefType:
                          type: string
                        minimumDeferredPayments:
                          type: integer
                        maximumDeferredPayments:
                          type: integer
                        principalForgiveness:
                          type: boolean
                        rateChange:
                          type: boolean
                    communication:
                      type: object
                      required:
                        - agreementTemplateCode
                        - invitationTemplateCode
                        - replacementTemplateCode
                        - reminderTemplateCode
                        - ineligibilityTemplateCode
                        - language
                        - offerValidityHours
                        - documentDeadlineHours
                        - reminderAfterHours
                      properties:
                        agreementTemplateCode:
                          type: string
                        invitationTemplateCode:
                          type: string
                        replacementTemplateCode:
                          type: string
                        reminderTemplateCode:
                          type: string
                        ineligibilityTemplateCode:
                          type: string
                        language:
                          type: string
                        offerValidityHours:
                          type: integer
                        documentDeadlineHours:
                          type: integer
                        reminderAfterHours:
                          type: integer
                    workflow:
                      type: object
                      required:
                        - caseType
                        - workflowKey
                      properties:
                        caseType:
                          type: string
                        workflowKey:
                          type: string
                reason:
                  type: string
              example:
                definition:
                  programCode: MEDICAL_LEAVE_DEFERRAL_V1
                  displayName: Medical Leave Deferral
                  hardshipReasonCode: MEDICAL_LEAVE
                  scope:
                    productClasses:
                      - COVERED_CONSUMER
                    jurisdictions:
                      - US
                    currencies:
                      - USD
                    repaymentFrequencies:
                      - MONTHLY
                    requiredNativeCapability: DEFER_SCHEDULED_INSTALLMENTS_TO_MATURITY
                  evidence:
                    requiredEvidenceCode: DOCTORS_MEDICAL_LEAVE_CERTIFICATE
                    acceptedScreeningResults:
                      - SCREENING_PASSED
                      - VERIFIED
                    humanConfirmationAccepted: true
                  rules:
                    - key: EMPLOYMENT_ACTIVE
                      fact: employmentActive
                      operator: EQ
                      value: "true"
                      onFail: INELIGIBLE
                      onMissing: MISSING_INFORMATION
                      operatorExplanation: The borrower must still be employed; this program defers payments during leave, it does not address
                        job loss.
                      borrowerSafeReason: EMPLOYMENT_NOT_ACTIVE
                    - key: LEAVE_DOCUMENTED
                      fact: certificateState
                      operator: EQ
                      value: COMPLETE
                      onFail: MISSING_INFORMATION
                      onMissing: MISSING_INFORMATION
                      operatorExplanation: The workflow must have confirmed a complete doctor certificate before eligibility is evaluated.
                      borrowerSafeReason: EVIDENCE_INCOMPLETE
                    - key: DELINQUENCY_WITHIN_GUARDRAIL
                      fact: daysOverdue
                      operator: LTE
                      value: "120"
                      onFail: INELIGIBLE
                      onMissing: PASS
                      operatorExplanation: Beyond the lender-configured arrears age this program is not the right instrument.
                      borrowerSafeReason: ARREARS_TOO_OLD
                  authority:
                    straightThroughMaximum: 3
                    humanApprovalMaximum: 6
                    humanApprovalPermission: APPROVE_SERVICING_HARDSHIP_DEFERRAL_UP_TO_6
                    outsideProgramAbove: 6
                  terms:
                    reliefType: DEFER_SCHEDULED_INSTALLMENTS_TO_MATURITY
                    minimumDeferredPayments: 1
                    maximumDeferredPayments: 6
                    principalForgiveness: false
                    rateChange: false
                  communication:
                    agreementTemplateCode: HARDSHIP_MEDICAL_LEAVE_AGREEMENT
                    invitationTemplateCode: HARDSHIP_CERTIFICATE_REQUEST
                    replacementTemplateCode: HARDSHIP_CERTIFICATE_REPLACEMENT
                    reminderTemplateCode: HARDSHIP_CERTIFICATE_REMINDER
                    ineligibilityTemplateCode: HARDSHIP_NOT_ELIGIBLE
                    language: en
                    offerValidityHours: 168
                    documentDeadlineHours: 168
                    reminderAfterHours: 72
                  workflow:
                    caseType: HARDSHIP_ASSISTANCE
                    workflowKey: MEDICAL_LEAVE_HARDSHIP_V1
                reason: Extends the arrears eligibility rule from 90 to 120 days overdue.
            example:
              definition:
                programCode: MEDICAL_LEAVE_DEFERRAL_V1
                displayName: Medical Leave Deferral
                hardshipReasonCode: MEDICAL_LEAVE
                scope:
                  productClasses:
                    - COVERED_CONSUMER
                  jurisdictions:
                    - US
                  currencies:
                    - USD
                  repaymentFrequencies:
                    - MONTHLY
                  requiredNativeCapability: DEFER_SCHEDULED_INSTALLMENTS_TO_MATURITY
                evidence:
                  requiredEvidenceCode: DOCTORS_MEDICAL_LEAVE_CERTIFICATE
                  acceptedScreeningResults:
                    - SCREENING_PASSED
                    - VERIFIED
                  humanConfirmationAccepted: true
                rules:
                  - key: EMPLOYMENT_ACTIVE
                    fact: employmentActive
                    operator: EQ
                    value: "true"
                    onFail: INELIGIBLE
                    onMissing: MISSING_INFORMATION
                    operatorExplanation: The borrower must still be employed; this program defers payments during leave, it does not address
                      job loss.
                    borrowerSafeReason: EMPLOYMENT_NOT_ACTIVE
                  - key: LEAVE_DOCUMENTED
                    fact: certificateState
                    operator: EQ
                    value: COMPLETE
                    onFail: MISSING_INFORMATION
                    onMissing: MISSING_INFORMATION
                    operatorExplanation: The workflow must have confirmed a complete doctor certificate before eligibility is evaluated.
                    borrowerSafeReason: EVIDENCE_INCOMPLETE
                  - key: DELINQUENCY_WITHIN_GUARDRAIL
                    fact: daysOverdue
                    operator: LTE
                    value: "120"
                    onFail: INELIGIBLE
                    onMissing: PASS
                    operatorExplanation: Beyond the lender-configured arrears age this program is not the right instrument.
                    borrowerSafeReason: ARREARS_TOO_OLD
                authority:
                  straightThroughMaximum: 3
                  humanApprovalMaximum: 6
                  humanApprovalPermission: APPROVE_SERVICING_HARDSHIP_DEFERRAL_UP_TO_6
                  outsideProgramAbove: 6
                terms:
                  reliefType: DEFER_SCHEDULED_INSTALLMENTS_TO_MATURITY
                  minimumDeferredPayments: 1
                  maximumDeferredPayments: 6
                  principalForgiveness: false
                  rateChange: false
                communication:
                  agreementTemplateCode: HARDSHIP_MEDICAL_LEAVE_AGREEMENT
                  invitationTemplateCode: HARDSHIP_CERTIFICATE_REQUEST
                  replacementTemplateCode: HARDSHIP_CERTIFICATE_REPLACEMENT
                  reminderTemplateCode: HARDSHIP_CERTIFICATE_REMINDER
                  ineligibilityTemplateCode: HARDSHIP_NOT_ELIGIBLE
                  language: en
                  offerValidityHours: 168
                  documentDeadlineHours: 168
                  reminderAfterHours: 72
                workflow:
                  caseType: HARDSHIP_ASSISTANCE
                  workflowKey: MEDICAL_LEAVE_HARDSHIP_V1
              reason: Extends the arrears eligibility rule from 90 to 120 days overdue.
  /v1/servicing/admin/hardship-policies/{programCode}/versions/{versionId}/validate:
    post:
      tags:
        - Hardship
      operationId: validateHardshipPolicyVersion
      summary: Validate a policy version
      description: Runs completeness, scope-overlap, template, workflow, permission, native-capability, and guardrail checks
        and records the verdict on the version. Any ERROR finding blocks activation.
      x-permission: ADMIN_SERVICING_HARDSHIP_POLICY
      x-idempotent: true
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: programCode
          in: path
          required: true
          description: Stable opaque programCode identifier.
          schema:
            type: string
        - name: versionId
          in: path
          required: true
          description: Stable opaque version identifier.
          schema:
            type: string
        - name: Idempotency-Key
          in: header
          required: false
          description: Optional replay key for this logical mutation. Omission creates a fresh server-owned key for this attempt;
            blank, repeated, or longer-than-50-character values are rejected.
          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:
                      - programVersionId
                      - operation
                      - valid
                      - findings
                    properties:
                      programVersionId:
                        type: integer
                      operation:
                        type: string
                      valid:
                        type: boolean
                      findings:
                        type: array
                        items:
                          type: string
              example:
                resourceId: 9302
                changes:
                  programVersionId: 9302
                  operation: VALIDATE
                  valid: true
                  findings:
                    - FIRST_ACTIVE_FOR_REASON
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
        "409":
          $ref: "#/components/responses/Servicing409Error"
  /v1/servicing/admin/hardship-policies/{programCode}/versions/{versionId}/simulate:
    post:
      tags:
        - Hardship
      operationId: simulateHardshipPolicyVersion
      summary: Simulate a policy version
      description: Runs the version's rules against a synthetic fact set and persists the always-synthetic run beside the
        version. Simulation never touches a case.
      x-permission: ADMIN_SERVICING_HARDSHIP_POLICY
      x-idempotent: true
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: programCode
          in: path
          required: true
          description: Stable opaque programCode identifier.
          schema:
            type: string
        - name: versionId
          in: path
          required: true
          description: Stable opaque version identifier.
          schema:
            type: string
        - name: Idempotency-Key
          in: header
          required: false
          description: Optional replay key for this logical mutation. Omission creates a fresh server-owned key for this attempt;
            blank, repeated, or longer-than-50-character values are rejected.
          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:
                      - programVersionId
                      - simulationId
                      - operation
                      - synthetic
                    properties:
                      programVersionId:
                        type: integer
                      simulationId:
                        type: integer
                      operation:
                        type: string
                      synthetic:
                        type: boolean
              example:
                resourceId: 8801
                changes:
                  programVersionId: 9302
                  simulationId: 8801
                  operation: SIMULATE
                  synthetic: true
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
        "409":
          $ref: "#/components/responses/Servicing409Error"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - requestedCount
                - facts
              properties:
                requestedCount:
                  type: integer
                facts:
                  type: object
                  required:
                    - employmentActive
                    - certificateState
                    - leaveStartDate
                    - expectedReturnDate
                    - canResumeAfterReturn
                    - loanStatus
                    - daysOverdue
                  properties:
                    employmentActive:
                      type: string
                    certificateState:
                      type: string
                    leaveStartDate:
                      type: string
                      format: date
                    expectedReturnDate:
                      type: string
                      format: date
                    canResumeAfterReturn:
                      type: string
                    loanStatus:
                      type: string
                    daysOverdue:
                      type: string
              example:
                requestedCount: 4
                facts:
                  employmentActive: "true"
                  certificateState: COMPLETE
                  leaveStartDate: 2026-07-14
                  expectedReturnDate: 2026-08-25
                  canResumeAfterReturn: "true"
                  loanStatus: ACTIVE
                  daysOverdue: "0"
            example:
              requestedCount: 4
              facts:
                employmentActive: "true"
                certificateState: COMPLETE
                leaveStartDate: 2026-07-14
                expectedReturnDate: 2026-08-25
                canResumeAfterReturn: "true"
                loanStatus: ACTIVE
                daysOverdue: "0"
  /v1/servicing/admin/hardship-policies/{programCode}/versions/{versionId}/activate:
    post:
      tags:
        - Hardship
      operationId: activateHardshipPolicyVersion
      summary: Activate a policy version
      description: Re-validates the version and puts it into force from the effective date, retiring the version it replaces
        in the same transaction. A version that does not validate is refused.
      x-permission: ACTIVATE_SERVICING_HARDSHIP_POLICY
      x-idempotent: true
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: programCode
          in: path
          required: true
          description: Stable opaque programCode identifier.
          schema:
            type: string
        - name: versionId
          in: path
          required: true
          description: Stable opaque version identifier.
          schema:
            type: string
        - name: Idempotency-Key
          in: header
          required: false
          description: Optional replay key for this logical mutation. Omission creates a fresh server-owned key for this attempt;
            blank, repeated, or longer-than-50-character values are rejected.
          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:
                      - programVersionId
                      - operation
                    properties:
                      programVersionId:
                        type: integer
                      operation:
                        type: string
              example:
                resourceId: 9302
                changes:
                  programVersionId: 9302
                  operation: ACTIVATE
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
        "409":
          $ref: "#/components/responses/Servicing409Error"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - effectiveFrom
                - reason
              properties:
                effectiveFrom:
                  type: string
                reason:
                  type: string
                expectedVersion:
                  type: integer
              example:
                effectiveFrom: 2026-08-01
                reason: Approved at the August credit policy review.
                expectedVersion: 2
            example:
              effectiveFrom: 2026-08-01
              reason: Approved at the August credit policy review.
              expectedVersion: 2
  /v1/servicing/admin/hardship-policies/{programCode}/versions/{versionId}/retire:
    post:
      tags:
        - Hardship
      operationId: retireHardshipPolicyVersion
      summary: Retire a policy version
      description: Takes a version out of force so it governs no new selections. Existing cases keep the version their
        decisions were evaluated under.
      x-permission: ACTIVATE_SERVICING_HARDSHIP_POLICY
      x-idempotent: true
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: programCode
          in: path
          required: true
          description: Stable opaque programCode identifier.
          schema:
            type: string
        - name: versionId
          in: path
          required: true
          description: Stable opaque version identifier.
          schema:
            type: string
        - name: Idempotency-Key
          in: header
          required: false
          description: Optional replay key for this logical mutation. Omission creates a fresh server-owned key for this attempt;
            blank, repeated, or longer-than-50-character values are rejected.
          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:
                      - programVersionId
                      - operation
                    properties:
                      programVersionId:
                        type: integer
                      operation:
                        type: string
              example:
                resourceId: 9302
                changes:
                  programVersionId: 9302
                  operation: RETIRE
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
        "409":
          $ref: "#/components/responses/Servicing409Error"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - reason
              properties:
                reason:
                  type: string
                expectedVersion:
                  type: integer
              example:
                reason: Superseded by the 2026 revision of the medical-leave programme.
                expectedVersion: 3
            example:
              reason: Superseded by the 2026 revision of the medical-leave programme.
              expectedVersion: 3
  /v1/servicing/admin/hardship-policies/guardrails:
    post:
      tags:
        - Hardship
      operationId: draftHardshipGuardrailVersion
      summary: Draft the next guardrail version
      description: Creates the next draft of the lender-wide guardrails every hardship program is held to. Parsing is strict
        and closed; a bound nobody declared is refused, never defaulted.
      x-permission: ADMIN_SERVICING_HARDSHIP_POLICY
      x-idempotent: true
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: Idempotency-Key
          in: header
          required: false
          description: Optional replay key for this logical mutation. Omission creates a fresh server-owned key for this attempt;
            blank, repeated, or longer-than-50-character values are rejected.
          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:
                      - guardrailVersionId
                      - operation
                    properties:
                      guardrailVersionId:
                        type: integer
                      operation:
                        type: string
              example:
                resourceId: 7502
                changes:
                  guardrailVersionId: 7502
                  operation: DRAFT
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
        "409":
          $ref: "#/components/responses/Servicing409Error"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - guardrails
                - reason
              properties:
                guardrails:
                  type: object
                  required:
                    - guardrailVersion
                    - minimumLoanAgeInstallments
                    - maximumActiveHardshipCasesPerLoan
                    - requireVerifiedContactForOffer
                    - requireWorkflowConfirmedEvidence
                    - prohibitPrincipalForgiveness
                    - prohibitRateChange
                    - specialistConditions
                    - offerValidityHoursMaximum
                    - documentDeadlineHoursMaximum
                    - maximumDeferredPayments
                    - reevaluateOnMaterialLoanDrift
                  properties:
                    guardrailVersion:
                      type: integer
                    minimumLoanAgeInstallments:
                      type: integer
                    maximumActiveHardshipCasesPerLoan:
                      type: integer
                    requireVerifiedContactForOffer:
                      type: boolean
                    requireWorkflowConfirmedEvidence:
                      type: boolean
                    prohibitPrincipalForgiveness:
                      type: boolean
                    prohibitRateChange:
                      type: boolean
                    specialistConditions:
                      type: array
                      items:
                        type: string
                    offerValidityHoursMaximum:
                      type: integer
                    documentDeadlineHoursMaximum:
                      type: integer
                    maximumDeferredPayments:
                      type: integer
                    reevaluateOnMaterialLoanDrift:
                      type: boolean
                reason:
                  type: string
              example:
                guardrails:
                  guardrailVersion: 2
                  minimumLoanAgeInstallments: 1
                  maximumActiveHardshipCasesPerLoan: 1
                  requireVerifiedContactForOffer: true
                  requireWorkflowConfirmedEvidence: true
                  prohibitPrincipalForgiveness: true
                  prohibitRateChange: true
                  specialistConditions:
                    - BANKRUPTCY
                    - LITIGATION
                    - FRAUD_INVESTIGATION
                    - DECEASED
                    - LEGAL_HOLD
                    - RECOVERY_PLACEMENT
                  offerValidityHoursMaximum: 168
                  documentDeadlineHoursMaximum: 504
                  maximumDeferredPayments: 6
                  reevaluateOnMaterialLoanDrift: true
                reason: Widens the document deadline from two weeks to three so declared-disaster relief can be drafted.
            example:
              guardrails:
                guardrailVersion: 2
                minimumLoanAgeInstallments: 1
                maximumActiveHardshipCasesPerLoan: 1
                requireVerifiedContactForOffer: true
                requireWorkflowConfirmedEvidence: true
                prohibitPrincipalForgiveness: true
                prohibitRateChange: true
                specialistConditions:
                  - BANKRUPTCY
                  - LITIGATION
                  - FRAUD_INVESTIGATION
                  - DECEASED
                  - LEGAL_HOLD
                  - RECOVERY_PLACEMENT
                offerValidityHoursMaximum: 168
                documentDeadlineHoursMaximum: 504
                maximumDeferredPayments: 6
                reevaluateOnMaterialLoanDrift: true
              reason: Widens the document deadline from two weeks to three so declared-disaster relief can be drafted.
  /v1/servicing/admin/hardship-policies/guardrails/{versionId}/validate:
    post:
      tags:
        - Hardship
      operationId: validateHardshipGuardrailVersion
      summary: Validate a guardrail version
      description: Checks the drafted guardrails against every active program and records the verdict; a proposed ceiling that
        an active program already exceeds is an ERROR finding.
      x-permission: ADMIN_SERVICING_HARDSHIP_POLICY
      x-idempotent: true
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: versionId
          in: path
          required: true
          description: Stable opaque version identifier.
          schema:
            type: string
        - name: Idempotency-Key
          in: header
          required: false
          description: Optional replay key for this logical mutation. Omission creates a fresh server-owned key for this attempt;
            blank, repeated, or longer-than-50-character values are rejected.
          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:
                      - guardrailVersionId
                      - operation
                      - valid
                      - findings
                    properties:
                      guardrailVersionId:
                        type: integer
                      operation:
                        type: string
                      valid:
                        type: boolean
                      findings:
                        type: array
                        items:
                          type: object
              example:
                resourceId: 7502
                changes:
                  guardrailVersionId: 7502
                  operation: VALIDATE
                  valid: true
                  findings: []
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
        "409":
          $ref: "#/components/responses/Servicing409Error"
  /v1/servicing/admin/hardship-policies/guardrails/{versionId}/activate:
    post:
      tags:
        - Hardship
      operationId: activateHardshipGuardrailVersion
      summary: Activate a guardrail version
      description: Puts the guardrail version into force as the single active portfolio ceiling, retiring its predecessor in
        the same transaction. The bounds take effect on the next policy validation.
      x-permission: ACTIVATE_SERVICING_HARDSHIP_POLICY
      x-idempotent: true
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: versionId
          in: path
          required: true
          description: Stable opaque version identifier.
          schema:
            type: string
        - name: Idempotency-Key
          in: header
          required: false
          description: Optional replay key for this logical mutation. Omission creates a fresh server-owned key for this attempt;
            blank, repeated, or longer-than-50-character values are rejected.
          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:
                      - guardrailVersionId
                      - operation
                    properties:
                      guardrailVersionId:
                        type: integer
                      operation:
                        type: string
              example:
                resourceId: 7502
                changes:
                  guardrailVersionId: 7502
                  operation: ACTIVATE
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
        "409":
          $ref: "#/components/responses/Servicing409Error"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - reason
              properties:
                reason:
                  type: string
                expectedVersion:
                  type: integer
              example:
                reason: Approved widening of the document deadline for declared-disaster relief.
                expectedVersion: 2
            example:
              reason: Approved widening of the document deadline for declared-disaster relief.
              expectedVersion: 2
  /v1/servicing/admin/hardship-policies/guardrails/{versionId}/retire:
    post:
      tags:
        - Hardship
      operationId: retireHardshipGuardrailVersion
      summary: Retire a guardrail version
      description: Takes a guardrail version out of force. With no active guardrails the portfolio reports invalid and no
        program version can validate or activate.
      x-permission: ACTIVATE_SERVICING_HARDSHIP_POLICY
      x-idempotent: true
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: versionId
          in: path
          required: true
          description: Stable opaque version identifier.
          schema:
            type: string
        - name: Idempotency-Key
          in: header
          required: false
          description: Optional replay key for this logical mutation. Omission creates a fresh server-owned key for this attempt;
            blank, repeated, or longer-than-50-character values are rejected.
          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:
                      - guardrailVersionId
                      - operation
                    properties:
                      guardrailVersionId:
                        type: integer
                      operation:
                        type: string
              example:
                resourceId: 7502
                changes:
                  guardrailVersionId: 7502
                  operation: RETIRE
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
        "409":
          $ref: "#/components/responses/Servicing409Error"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - reason
              properties:
                reason:
                  type: string
                expectedVersion:
                  type: integer
              example:
                reason: Retired in favor of the recalibrated 2026 guardrail set.
                expectedVersion: 3
            example:
              reason: Retired in favor of the recalibrated 2026 guardrail set.
              expectedVersion: 3
  /v1/servicing/cases/{caseId}/hardship:
    get:
      tags:
        - Hardship
      operationId: getCaseHardship
      summary: Retrieve the composed hardship workspace
      description: "Returns the one composed hardship read: origin, typed leave facts with provenance, evidence invitations
        and screenings, the pinned policy decision and trace, the proposed native financial preview, offer versions,
        correspondence extractions, upcoming stages, and the stated build boundary. Protected extracted certificate
        values are withheld without the sensitive-document permission."
      x-permission: READ_SERVICING_CASE
      x-idempotent: false
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: caseId
          in: path
          required: true
          description: Positive numeric case identifier.
          schema:
            type: integer
            format: int64
            minimum: 1
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - caseId
                  - source
                  - leaveFacts
                  - evidence
                  - policy
                  - financialPreview
                  - offers
                  - correspondence
                  - upcoming
                  - boundary
                properties:
                  caseId:
                    type: integer
                    description: Stable opaque servicing case identifier.
                  source:
                    type: object
                    description: System or actor that originated the record.
                    required:
                      - collectionsCase
                      - sourceInteraction
                    properties:
                      collectionsCase:
                        type: object
                        required:
                          - caseId
                          - externalCaseRef
                          - status
                          - outcomeCode
                          - closureReason
                          - relationshipLabel
                        properties:
                          caseId:
                            type: integer
                            description: Stable opaque servicing case identifier.
                          externalCaseRef:
                            type: string
                          status:
                            type: string
                            description: Current normalized lifecycle state.
                          outcomeCode:
                            type: string
                          closureReason:
                            type: string
                          relationshipLabel:
                            type: string
                      sourceInteraction:
                        type: object
                        required:
                          - interactionId
                          - channel
                          - direction
                          - occurredAt
                          - verificationState
                          - summary
                          - performedBy
                        properties:
                          interactionId:
                            type: integer
                          channel:
                            type: string
                          direction:
                            type: string
                          occurredAt:
                            type: string
                            format: date-time
                          verificationState:
                            type: string
                          summary:
                            type: string
                          performedBy:
                            type: string
                  leaveFacts:
                    type: object
                    required:
                      - dataVersion
                      - programCode
                      - hardshipReasonCode
                      - employmentActive
                      - leaveStartDate
                      - expectedReturnDate
                      - canResumeAfterReturn
                      - requestedDeferredPayments
                      - certificateState
                      - sources
                      - history
                    properties:
                      dataVersion:
                        type: integer
                      programCode:
                        type: string
                      hardshipReasonCode:
                        type: string
                      employmentActive:
                        type: boolean
                      leaveStartDate:
                        type: string
                        format: date
                      expectedReturnDate:
                        type: string
                        format: date
                      canResumeAfterReturn:
                        type: boolean
                      requestedDeferredPayments:
                        type: integer
                      certificateState:
                        type: string
                      sources:
                        type: object
                        required:
                          - leaveStartDate
                          - requestedDeferredPayments
                        properties:
                          leaveStartDate:
                            type: object
                            required:
                              - source
                              - asOf
                              - confidence
                            properties:
                              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.
                              confidence:
                                type: number
                          requestedDeferredPayments:
                            type: object
                            required:
                              - source
                              - asOf
                            properties:
                              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.
                      history:
                        type: array
                        items:
                          type: object
                          required:
                            - dataVersion
                            - certificateState
                            - requestedDeferredPayments
                            - changeReason
                            - actorType
                            - recordedAt
                          properties:
                            dataVersion:
                              type: integer
                            certificateState:
                              type: string
                            requestedDeferredPayments:
                              type: integer
                            changeReason:
                              type: string
                            actorType:
                              type: string
                            recordedAt:
                              type: string
                              format: date-time
                  evidence:
                    type: object
                    required:
                      - invitations
                      - analyses
                    properties:
                      invitations:
                        type: array
                        items:
                          type: object
                          required:
                            - invitationRef
                            - evidenceType
                            - state
                            - issuedAt
                            - expiresAt
                            - deliveredAt
                            - openedAt
                            - uploadedAt
                            - revokedAt
                          properties:
                            invitationRef:
                              type: string
                            evidenceType:
                              type: string
                            state:
                              type: string
                            issuedAt:
                              type: string
                              format: date-time
                            expiresAt:
                              type: string
                              format: date-time
                            deliveredAt:
                              type: string
                              format: date-time
                            openedAt:
                              type: string
                              format: date-time
                            uploadedAt:
                              type: string
                              format: date-time
                            revokedAt:
                              type: string
                              format: date-time
                      analyses:
                        type: array
                        items:
                          type: object
                          required:
                            - analysisId
                            - documentId
                            - documentRef
                            - classification
                            - classificationConfidence
                            - result
                            - resultConfidence
                            - resultLabel
                            - verificationBasis
                            - concerns
                            - reasonCodes
                            - workerCode
                            - runtimeRelease
                            - policyVersion
                            - packetVersion
                            - humanDecision
                            - humanDecisionReason
                            - humanDecidedAt
                            - reviewTaskId
                            - screenedAt
                            - extractedFieldsWithheld
                          properties:
                            analysisId:
                              type: integer
                            documentId:
                              type: integer
                            documentRef:
                              type: string
                            classification:
                              type: string
                            classificationConfidence:
                              type: number
                            result:
                              type: string
                            resultConfidence:
                              type: number
                            resultLabel:
                              type: string
                            verificationBasis:
                              type: string
                            concerns:
                              type: array
                              items:
                                type: object
                            reasonCodes:
                              type: array
                              items:
                                type: object
                            workerCode:
                              type: string
                            runtimeRelease:
                              type: string
                            policyVersion:
                              type: string
                            packetVersion:
                              type: string
                            humanDecision:
                              type: string
                            humanDecisionReason:
                              type: string
                            humanDecidedAt:
                              type: string
                              format: date-time
                            reviewTaskId:
                              type: string
                            screenedAt:
                              type: string
                              format: date-time
                            extractedFieldsWithheld:
                              type: boolean
                  policy:
                    type: object
                    required:
                      - currentDecision
                      - supersededDecisions
                    properties:
                      currentDecision:
                        type: object
                        required:
                          - decisionRef
                          - programCode
                          - programVersion
                          - definitionDigest
                          - result
                          - requestedCount
                          - allowedCount
                          - requiredPermission
                          - reasonCodes
                          - ruleTrace
                          - inputSnapshot
                          - inputDigest
                          - caseDataVersion
                          - permittedNextActions
                          - evaluatedAt
                        properties:
                          decisionRef:
                            type: string
                          programCode:
                            type: string
                          programVersion:
                            type: integer
                          definitionDigest:
                            type: string
                          result:
                            type: string
                          requestedCount:
                            type: integer
                          allowedCount:
                            type: integer
                          requiredPermission:
                            type: string
                          reasonCodes:
                            type: array
                            items:
                              type: object
                          ruleTrace:
                            type: array
                            items:
                              type: object
                              required:
                                - key
                                - fact
                                - operator
                                - expected
                                - observed
                                - status
                                - operatorExplanation
                              properties:
                                key:
                                  type: string
                                fact:
                                  type: string
                                operator:
                                  type: string
                                expected:
                                  type: string
                                observed:
                                  type: string
                                status:
                                  type: string
                                  description: Current normalized lifecycle state.
                                operatorExplanation:
                                  type: string
                          inputSnapshot:
                            type: object
                            required:
                              - programCode
                              - requestedCount
                              - caseDataVersion
                              - facts
                            properties:
                              programCode:
                                type: string
                              requestedCount:
                                type: integer
                              caseDataVersion:
                                type: integer
                              facts:
                                type: object
                                required:
                                  - employmentActive
                                properties:
                                  employmentActive:
                                    type: object
                                    required:
                                      - value
                                      - source
                                      - asOf
                                    properties:
                                      value:
                                        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.
                          inputDigest:
                            type: string
                          caseDataVersion:
                            type: integer
                          permittedNextActions:
                            type: array
                            items:
                              type: string
                          evaluatedAt:
                            type: string
                            format: date-time
                      supersededDecisions:
                        type: array
                        items:
                          type: object
                  financialPreview:
                    type: object
                    required:
                      - source
                      - label
                      - proposals
                      - current
                      - optionComparison
                    properties:
                      source:
                        type: string
                        description: System or actor that originated the record.
                      label:
                        type: string
                      proposals:
                        type: array
                        items:
                          type: object
                          required:
                            - proposalId
                            - deferredInstallmentCount
                            - state
                            - previewDigest
                            - previewAsOf
                            - failureCode
                            - retireReason
                            - retiredAt
                          properties:
                            proposalId:
                              type: integer
                            deferredInstallmentCount:
                              type: integer
                            state:
                              type: string
                            previewDigest:
                              type: string
                            previewAsOf:
                              type: string
                            failureCode:
                              type: string
                            retireReason:
                              type: string
                            retiredAt:
                              type: string
                              format: date-time
                      current:
                        type: object
                        required:
                          - sourceSystem
                          - asOf
                          - businessDate
                          - deferredInstallmentCount
                          - paymentResumptionDate
                          - currentMaturityDate
                          - proposedMaturityDate
                          - currencyCode
                          - deferredTotalAmount
                          - totalCostDelta
                          - currentTotalRepayment
                          - proposedTotalRepayment
                          - affectedInstallments
                          - previewDigest
                        properties:
                          sourceSystem:
                            type: string
                          asOf:
                            type: string
                            format: date-time
                            description: Time at which the source says the fact was true.
                          businessDate:
                            type: string
                            format: date
                          deferredInstallmentCount:
                            type: integer
                          paymentResumptionDate:
                            type: string
                            format: date
                          currentMaturityDate:
                            type: string
                            format: date
                          proposedMaturityDate:
                            type: string
                            format: date
                          currencyCode:
                            type: string
                          deferredTotalAmount:
                            type: string
                          totalCostDelta:
                            type: string
                          currentTotalRepayment:
                            type: string
                          proposedTotalRepayment:
                            type: string
                          affectedInstallments:
                            type: array
                            items:
                              type: object
                              required:
                                - installmentNumber
                                - currentDueDate
                                - proposedDueDate
                                - principal
                                - interest
                                - fees
                                - total
                              properties:
                                installmentNumber:
                                  type: integer
                                currentDueDate:
                                  type: string
                                  format: date
                                proposedDueDate:
                                  type: string
                                  format: date
                                principal:
                                  type: string
                                interest:
                                  type: string
                                fees:
                                  type: string
                                total:
                                  type: string
                          previewDigest:
                            type: string
                      optionComparison:
                        type: array
                        items:
                          type: object
                          required:
                            - deferredInstallmentCount
                            - state
                            - preview
                          properties:
                            deferredInstallmentCount:
                              type: integer
                            state:
                              type: string
                            preview:
                              type: object
                              required:
                                - sourceSystem
                                - asOf
                                - businessDate
                                - deferredInstallmentCount
                                - paymentResumptionDate
                                - currentMaturityDate
                                - proposedMaturityDate
                                - currencyCode
                                - deferredTotalAmount
                                - totalCostDelta
                                - currentTotalRepayment
                                - proposedTotalRepayment
                                - affectedInstallments
                                - previewDigest
                              properties:
                                sourceSystem:
                                  type: string
                                asOf:
                                  type: string
                                  format: date-time
                                  description: Time at which the source says the fact was true.
                                businessDate:
                                  type: string
                                  format: date
                                deferredInstallmentCount:
                                  type: integer
                                paymentResumptionDate:
                                  type: string
                                  format: date
                                currentMaturityDate:
                                  type: string
                                  format: date
                                proposedMaturityDate:
                                  type: string
                                  format: date
                                currencyCode:
                                  type: string
                                deferredTotalAmount:
                                  type: string
                                totalCostDelta:
                                  type: string
                                currentTotalRepayment:
                                  type: string
                                proposedTotalRepayment:
                                  type: string
                                affectedInstallments:
                                  type: array
                                  items:
                                    type: object
                                    required:
                                      - installmentNumber
                                      - currentDueDate
                                      - proposedDueDate
                                      - principal
                                      - interest
                                      - fees
                                      - total
                                    properties:
                                      installmentNumber:
                                        type: integer
                                      currentDueDate:
                                        type: string
                                        format: date
                                      proposedDueDate:
                                        type: string
                                        format: date
                                      principal:
                                        type: string
                                      interest:
                                        type: string
                                      fees:
                                        type: string
                                      total:
                                        type: string
                                previewDigest:
                                  type: string
                  offers:
                    type: object
                    required:
                      - versions
                      - currentOfferId
                    properties:
                      versions:
                        type: array
                        items:
                          type: object
                          required:
                            - offerId
                            - offerRef
                            - offerVersion
                            - deferredPaymentCount
                            - status
                            - statusReason
                            - issuedAt
                            - expiresAt
                            - approvedAt
                            - approvalPermission
                            - supersededByOfferId
                            - templateCode
                            - templateVersion
                            - renderedDigest
                            - previewDigest
                            - terms
                          properties:
                            offerId:
                              type: integer
                            offerRef:
                              type: string
                            offerVersion:
                              type: integer
                            deferredPaymentCount:
                              type: integer
                            status:
                              type: string
                              description: Current normalized lifecycle state.
                            statusReason:
                              type: string
                            issuedAt:
                              type: string
                              format: date-time
                            expiresAt:
                              type: string
                              format: date-time
                            approvedAt:
                              type: string
                              format: date-time
                            approvalPermission:
                              type: string
                            supersededByOfferId:
                              type: string
                            templateCode:
                              type: string
                            templateVersion:
                              type: integer
                            renderedDigest:
                              type: string
                            previewDigest:
                              type: string
                            terms:
                              type: object
                              required:
                                - reliefType
                                - deferredPaymentCount
                                - principalForgiveness
                                - rateChange
                                - preview
                                - display
                              properties:
                                reliefType:
                                  type: string
                                deferredPaymentCount:
                                  type: integer
                                principalForgiveness:
                                  type: boolean
                                rateChange:
                                  type: boolean
                                preview:
                                  type: object
                                  required:
                                    - sourceSystem
                                    - asOf
                                    - businessDate
                                    - deferredInstallmentCount
                                    - paymentResumptionDate
                                    - currentMaturityDate
                                    - proposedMaturityDate
                                    - currencyCode
                                    - deferredTotalAmount
                                    - totalCostDelta
                                    - currentTotalRepayment
                                    - proposedTotalRepayment
                                    - affectedInstallments
                                    - previewDigest
                                  properties:
                                    sourceSystem:
                                      type: string
                                    asOf:
                                      type: string
                                      format: date-time
                                      description: Time at which the source says the fact was true.
                                    businessDate:
                                      type: string
                                      format: date
                                    deferredInstallmentCount:
                                      type: integer
                                    paymentResumptionDate:
                                      type: string
                                      format: date
                                    currentMaturityDate:
                                      type: string
                                      format: date
                                    proposedMaturityDate:
                                      type: string
                                      format: date
                                    currencyCode:
                                      type: string
                                    deferredTotalAmount:
                                      type: string
                                    totalCostDelta:
                                      type: string
                                    currentTotalRepayment:
                                      type: string
                                    proposedTotalRepayment:
                                      type: string
                                    affectedInstallments:
                                      type: array
                                      items:
                                        type: object
                                        required:
                                          - installmentNumber
                                          - currentDueDate
                                          - proposedDueDate
                                          - principal
                                          - interest
                                          - fees
                                          - total
                                        properties:
                                          installmentNumber:
                                            type: integer
                                          currentDueDate:
                                            type: string
                                            format: date
                                          proposedDueDate:
                                            type: string
                                            format: date
                                          principal:
                                            type: string
                                          interest:
                                            type: string
                                          fees:
                                            type: string
                                          total:
                                            type: string
                                    previewDigest:
                                      type: string
                                display:
                                  type: object
                                  required:
                                    - deferredTotalAmount
                                    - totalCostDelta
                                    - affectedInstallmentDates
                                    - offerExpiryDate
                                    - borrowerTimeZone
                                    - offerReference
                                  properties:
                                    deferredTotalAmount:
                                      type: string
                                    totalCostDelta:
                                      type: string
                                    affectedInstallmentDates:
                                      type: string
                                    offerExpiryDate:
                                      type: string
                                      format: date
                                    borrowerTimeZone:
                                      type: string
                                    offerReference:
                                      type: string
                      currentOfferId:
                        type: integer
                  correspondence:
                    type: object
                    required:
                      - extractions
                    properties:
                      extractions:
                        type: array
                        items:
                          type: object
                          required:
                            - extractionId
                            - messageId
                            - threadId
                            - intent
                            - requestedDeferredPayments
                            - confidence
                            - summary
                            - borrowerQuestions
                            - safetyCodes
                            - workerCode
                            - runtimeRelease
                            - accepted
                            - reviewTaskId
                            - extractedAt
                          properties:
                            extractionId:
                              type: integer
                            messageId:
                              type: integer
                            threadId:
                              type: integer
                            intent:
                              type: string
                            requestedDeferredPayments:
                              type: integer
                            confidence:
                              type: number
                            summary:
                              type: string
                            borrowerQuestions:
                              type: array
                              items:
                                type: string
                            safetyCodes:
                              type: array
                              items:
                                type: object
                            workerCode:
                              type: string
                            runtimeRelease:
                              type: string
                            accepted:
                              type: boolean
                            reviewTaskId:
                              type: string
                            extractedAt:
                              type: string
                              format: date-time
                  upcoming:
                    type: object
                    required:
                      - stages
                    properties:
                      stages:
                        type: array
                        items:
                          type: object
                          required:
                            - stageKey
                            - status
                            - enteredAt
                            - exitedAt
                            - exitReason
                          properties:
                            stageKey:
                              type: string
                            status:
                              type: string
                              description: Current normalized lifecycle state.
                            enteredAt:
                              type: string
                              format: date-time
                            exitedAt:
                              type: string
                              format: date-time
                            exitReason:
                              type: string
                  boundary:
                    type: object
                    required:
                      - terminalStateThisPhase
                      - loanModified
                      - deferredCapabilities
                      - note
                    properties:
                      terminalStateThisPhase:
                        type: string
                      loanModified:
                        type: boolean
                      deferredCapabilities:
                        type: array
                        items:
                          type: string
                      note:
                        type: string
              example:
                caseId: 1001
                source:
                  collectionsCase:
                    caseId: 1000
                    externalCaseRef: LE-CASE-1000
                    status: OPEN
                    outcomeCode: null
                    closureReason: null
                    relationshipLabel: Originated from
                  sourceInteraction:
                    interactionId: 3001
                    channel: PHONE
                    direction: OUTBOUND
                    occurredAt: 2026-07-25T17:55:00Z
                    verificationState: VERIFIED
                    summary: Borrower reported surgery and six weeks of certified medical leave.
                    performedBy: Maria Agent
                leaveFacts:
                  dataVersion: 2
                  programCode: MEDICAL_LEAVE_DEFERRAL_V1
                  hardshipReasonCode: MEDICAL_LEAVE
                  employmentActive: true
                  leaveStartDate: 2026-07-14
                  expectedReturnDate: 2026-08-25
                  canResumeAfterReturn: true
                  requestedDeferredPayments: 4
                  certificateState: COMPLETE
                  sources:
                    leaveStartDate:
                      source: CERTIFICATE
                      asOf: 2026-07-25T18:20:00Z
                      confidence: 0.96
                    requestedDeferredPayments:
                      source: BORROWER_STATEMENT
                      asOf: 2026-07-25T17:55:00Z
                  history:
                    - dataVersion: 2
                      certificateState: COMPLETE
                      requestedDeferredPayments: 4
                      changeReason: Requested count updated from the borrower reply.
                      actorType: HUMAN
                      recordedAt: 2026-07-27T09:10:00Z
                evidence:
                  invitations:
                    - invitationRef: LE-UPL-4201
                      evidenceType: DOCTORS_MEDICAL_LEAVE_CERTIFICATE
                      state: UPLOADED
                      issuedAt: 2026-07-25T18:00:00Z
                      expiresAt: 2026-08-01T18:00:00Z
                      deliveredAt: 2026-07-25T18:01:00Z
                      openedAt: 2026-07-25T18:05:00Z
                      uploadedAt: 2026-07-25T18:12:00Z
                      revokedAt: null
                  analyses:
                    - analysisId: 8601
                      documentId: 7001
                      documentRef: LE-DOC-7001
                      classification: DOCTORS_MEDICAL_LEAVE_CERTIFICATE
                      classificationConfidence: 0.97
                      result: SCREENING_PASSED
                      resultConfidence: 0.94
                      resultLabel: No manipulation indicators were detected
                      verificationBasis: AI_SCREENING_ONLY
                      concerns: []
                      reasonCodes: []
                      workerCode: DOCUMENT_EVIDENCE_AGENT
                      runtimeRelease: runtime-2026.07
                      policyVersion: policy-12
                      packetVersion: packet-v1
                      humanDecision: null
                      humanDecisionReason: null
                      humanDecidedAt: null
                      reviewTaskId: null
                      screenedAt: 2026-07-25T18:20:00Z
                      extractedFieldsWithheld: true
                policy:
                  currentDecision:
                    decisionRef: LE-HPD-9f2c41d6a0b3
                    programCode: MEDICAL_LEAVE_DEFERRAL_V1
                    programVersion: 1
                    definitionDigest: 5d20c7e1a94f6b83
                    result: HUMAN_APPROVAL_REQUIRED
                    requestedCount: 4
                    allowedCount: 4
                    requiredPermission: APPROVE_SERVICING_HARDSHIP_DEFERRAL_UP_TO_6
                    reasonCodes: []
                    ruleTrace:
                      - key: EMPLOYMENT_ACTIVE
                        fact: employmentActive
                        operator: EQ
                        expected: "true"
                        observed: "true"
                        status: PASS
                        operatorExplanation: The borrower must still be employed; this program defers payments during leave, it does not address
                          job loss.
                    inputSnapshot:
                      programCode: MEDICAL_LEAVE_DEFERRAL_V1
                      requestedCount: 4
                      caseDataVersion: 2
                      facts:
                        employmentActive:
                          value: "true"
                          source: CASE_DATA
                          asOf: 2026-07-25T18:20:00Z
                    inputDigest: 77b3e9c04a5d812f
                    caseDataVersion: 2
                    permittedNextActions:
                      - PREPARE_NATIVE_PREVIEW
                      - PREPARE_OFFER
                      - CREATE_APPROVAL_TASK
                    evaluatedAt: 2026-07-27T09:12:00Z
                  supersededDecisions: []
                financialPreview:
                  source: LENDEASY_LMS_NATIVE_PREVIEW
                  label: Proposed — the loan has not changed
                  proposals:
                    - proposalId: 5601
                      deferredInstallmentCount: 4
                      state: OFFER_BOUND
                      previewDigest: 9c41f0b2a6d84e17
                      previewAsOf: 2026-07-27T09:14:00Z
                      failureCode: null
                      retireReason: null
                      retiredAt: null
                  current:
                    sourceSystem: LENDEASY_LMS
                    asOf: 2026-07-27T09:14:00Z
                    businessDate: 2026-07-27
                    deferredInstallmentCount: 4
                    paymentResumptionDate: 2026-12-01
                    currentMaturityDate: 2028-07-01
                    proposedMaturityDate: 2028-11-01
                    currencyCode: USD
                    deferredTotalAmount: "1540.00"
                    totalCostDelta: "51.20"
                    currentTotalRepayment: "11520.00"
                    proposedTotalRepayment: "11571.20"
                    affectedInstallments:
                      - installmentNumber: 13
                        currentDueDate: 2026-08-01
                        proposedDueDate: 2028-08-01
                        principal: "385.00"
                        interest: "35.00"
                        fees: "0.00"
                        total: "420.00"
                    previewDigest: 9c41f0b2a6d84e17
                  optionComparison:
                    - deferredInstallmentCount: 4
                      state: OFFER_BOUND
                      preview:
                        sourceSystem: LENDEASY_LMS
                        asOf: 2026-07-27T09:14:00Z
                        businessDate: 2026-07-27
                        deferredInstallmentCount: 4
                        paymentResumptionDate: 2026-12-01
                        currentMaturityDate: 2028-07-01
                        proposedMaturityDate: 2028-11-01
                        currencyCode: USD
                        deferredTotalAmount: "1540.00"
                        totalCostDelta: "51.20"
                        currentTotalRepayment: "11520.00"
                        proposedTotalRepayment: "11571.20"
                        affectedInstallments:
                          - installmentNumber: 13
                            currentDueDate: 2026-08-01
                            proposedDueDate: 2028-08-01
                            principal: "385.00"
                            interest: "35.00"
                            fees: "0.00"
                            total: "420.00"
                        previewDigest: 9c41f0b2a6d84e17
                offers:
                  versions:
                    - offerId: 6001
                      offerRef: LE-OFR-6001
                      offerVersion: 2
                      deferredPaymentCount: 4
                      status: READY_TO_SEND
                      statusReason: null
                      issuedAt: 2026-07-27T09:20:00Z
                      expiresAt: 2026-08-03T09:20:00Z
                      approvedAt: null
                      approvalPermission: APPROVE_SERVICING_HARDSHIP_DEFERRAL_UP_TO_6
                      supersededByOfferId: null
                      templateCode: HARDSHIP_MEDICAL_LEAVE_AGREEMENT
                      templateVersion: 1
                      renderedDigest: 4e9a1c7f52d0b386
                      previewDigest: 9c41f0b2a6d84e17
                      terms:
                        reliefType: DEFER_SCHEDULED_INSTALLMENTS_TO_MATURITY
                        deferredPaymentCount: 4
                        principalForgiveness: false
                        rateChange: false
                        preview:
                          sourceSystem: LENDEASY_LMS
                          asOf: 2026-07-27T09:14:00Z
                          businessDate: 2026-07-27
                          deferredInstallmentCount: 4
                          paymentResumptionDate: 2026-12-01
                          currentMaturityDate: 2028-07-01
                          proposedMaturityDate: 2028-11-01
                          currencyCode: USD
                          deferredTotalAmount: "1540.00"
                          totalCostDelta: "51.20"
                          currentTotalRepayment: "11520.00"
                          proposedTotalRepayment: "11571.20"
                          affectedInstallments:
                            - installmentNumber: 13
                              currentDueDate: 2026-08-01
                              proposedDueDate: 2028-08-01
                              principal: "385.00"
                              interest: "35.00"
                              fees: "0.00"
                              total: "420.00"
                          previewDigest: 9c41f0b2a6d84e17
                        display:
                          deferredTotalAmount: USD 1,540.00
                          totalCostDelta: USD 51.20
                          affectedInstallmentDates: 2026-08-01, 2026-09-01, 2026-10-01, 2026-11-01
                          offerExpiryDate: 2026-08-03
                          borrowerTimeZone: America/New_York
                          offerReference: LE-OFR-6001
                  currentOfferId: 6001
                correspondence:
                  extractions:
                    - extractionId: 4501
                      messageId: 9101
                      threadId: 8802
                      intent: REQUEST_DIFFERENT_HARDSHIP_TERMS
                      requestedDeferredPayments: 4
                      confidence: 0.92
                      summary: Borrower asked for four deferred payments instead of the offered three.
                      borrowerQuestions:
                        - Will this affect my credit report?
                      safetyCodes: []
                      workerCode: HARDSHIP_CORRESPONDENCE_AGENT
                      runtimeRelease: runtime-2026.07
                      accepted: true
                      reviewTaskId: null
                      extractedAt: 2026-07-27T09:10:00Z
                upcoming:
                  stages:
                    - stageKey: EVALUATE_CHANGE_REQUEST
                      status: COMPLETED
                      enteredAt: 2026-07-27T09:05:00Z
                      exitedAt: 2026-07-27T09:15:00Z
                      exitReason: null
                    - stageKey: HUMAN_DECISION_AND_SEND
                      status: CURRENT
                      enteredAt: 2026-07-27T09:15:00Z
                      exitedAt: null
                      exitReason: null
                boundary:
                  terminalStateThisPhase: WAITING_ON_BORROWER
                  loanModified: false
                  deferredCapabilities:
                    - BORROWER_ACCEPTANCE
                    - ELECTRONIC_SIGNATURE
                    - RESCHEDULE_EXECUTION
                    - SCHEDULE_CONFIRMATION
                    - CASE_CLOSURE_ON_ACTIVATION
                  note: The agreement is proposed. Nothing on the loan has changed and no acceptance has been recorded.
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
  /v1/servicing/cases/{caseId}/hardship/offers:
    get:
      tags:
        - Hardship
      operationId: listCaseHardshipOffers
      summary: List a case's hardship offers
      description: Lists every offer version for the case with server-derived terms, template provenance, and approval
        metadata. Offers are versions; a change produces a replacement, never an edit.
      x-permission: READ_SERVICING_CASE
      x-idempotent: false
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: caseId
          in: path
          required: true
          description: Positive numeric case identifier.
          schema:
            type: integer
            format: int64
            minimum: 1
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - caseId
                  - offers
                properties:
                  caseId:
                    type: integer
                    description: Stable opaque servicing case identifier.
                  offers:
                    type: array
                    items:
                      type: object
                      required:
                        - offerId
                        - offerRef
                        - offerVersion
                        - deferredPaymentCount
                        - status
                        - statusReason
                        - issuedAt
                        - expiresAt
                        - approvedAt
                        - approvalPermission
                        - supersededByOfferId
                        - templateCode
                        - templateVersion
                        - renderedDigest
                        - previewDigest
                        - terms
                      properties:
                        offerId:
                          type: integer
                        offerRef:
                          type: string
                        offerVersion:
                          type: integer
                        deferredPaymentCount:
                          type: integer
                        status:
                          type: string
                          description: Current normalized lifecycle state.
                        statusReason:
                          type: string
                        issuedAt:
                          type: string
                          format: date-time
                        expiresAt:
                          type: string
                          format: date-time
                        approvedAt:
                          type: string
                          format: date-time
                        approvalPermission:
                          type: string
                        supersededByOfferId:
                          type: string
                        templateCode:
                          type: string
                        templateVersion:
                          type: integer
                        renderedDigest:
                          type: string
                        previewDigest:
                          type: string
                        terms:
                          type: object
                          required:
                            - reliefType
                            - deferredPaymentCount
                            - principalForgiveness
                            - rateChange
                            - preview
                            - display
                          properties:
                            reliefType:
                              type: string
                            deferredPaymentCount:
                              type: integer
                            principalForgiveness:
                              type: boolean
                            rateChange:
                              type: boolean
                            preview:
                              type: object
                              required:
                                - sourceSystem
                                - asOf
                                - businessDate
                                - deferredInstallmentCount
                                - paymentResumptionDate
                                - currentMaturityDate
                                - proposedMaturityDate
                                - currencyCode
                                - deferredTotalAmount
                                - totalCostDelta
                                - currentTotalRepayment
                                - proposedTotalRepayment
                                - affectedInstallments
                                - previewDigest
                              properties:
                                sourceSystem:
                                  type: string
                                asOf:
                                  type: string
                                  format: date-time
                                  description: Time at which the source says the fact was true.
                                businessDate:
                                  type: string
                                  format: date
                                deferredInstallmentCount:
                                  type: integer
                                paymentResumptionDate:
                                  type: string
                                  format: date
                                currentMaturityDate:
                                  type: string
                                  format: date
                                proposedMaturityDate:
                                  type: string
                                  format: date
                                currencyCode:
                                  type: string
                                deferredTotalAmount:
                                  type: string
                                totalCostDelta:
                                  type: string
                                currentTotalRepayment:
                                  type: string
                                proposedTotalRepayment:
                                  type: string
                                affectedInstallments:
                                  type: array
                                  items:
                                    type: object
                                    required:
                                      - installmentNumber
                                      - currentDueDate
                                      - proposedDueDate
                                      - principal
                                      - interest
                                      - fees
                                      - total
                                    properties:
                                      installmentNumber:
                                        type: integer
                                      currentDueDate:
                                        type: string
                                        format: date
                                      proposedDueDate:
                                        type: string
                                        format: date
                                      principal:
                                        type: string
                                      interest:
                                        type: string
                                      fees:
                                        type: string
                                      total:
                                        type: string
                                previewDigest:
                                  type: string
                            display:
                              type: object
                              required:
                                - deferredTotalAmount
                                - totalCostDelta
                                - affectedInstallmentDates
                                - offerExpiryDate
                                - borrowerTimeZone
                                - offerReference
                              properties:
                                deferredTotalAmount:
                                  type: string
                                totalCostDelta:
                                  type: string
                                affectedInstallmentDates:
                                  type: string
                                offerExpiryDate:
                                  type: string
                                  format: date
                                borrowerTimeZone:
                                  type: string
                                offerReference:
                                  type: string
              example:
                caseId: 1001
                offers:
                  - offerId: 6001
                    offerRef: LE-OFR-6001
                    offerVersion: 2
                    deferredPaymentCount: 4
                    status: READY_TO_SEND
                    statusReason: null
                    issuedAt: 2026-07-27T09:20:00Z
                    expiresAt: 2026-08-03T09:20:00Z
                    approvedAt: null
                    approvalPermission: APPROVE_SERVICING_HARDSHIP_DEFERRAL_UP_TO_6
                    supersededByOfferId: null
                    templateCode: HARDSHIP_MEDICAL_LEAVE_AGREEMENT
                    templateVersion: 1
                    renderedDigest: 4e9a1c7f52d0b386
                    previewDigest: 9c41f0b2a6d84e17
                    terms:
                      reliefType: DEFER_SCHEDULED_INSTALLMENTS_TO_MATURITY
                      deferredPaymentCount: 4
                      principalForgiveness: false
                      rateChange: false
                      preview:
                        sourceSystem: LENDEASY_LMS
                        asOf: 2026-07-27T09:14:00Z
                        businessDate: 2026-07-27
                        deferredInstallmentCount: 4
                        paymentResumptionDate: 2026-12-01
                        currentMaturityDate: 2028-07-01
                        proposedMaturityDate: 2028-11-01
                        currencyCode: USD
                        deferredTotalAmount: "1540.00"
                        totalCostDelta: "51.20"
                        currentTotalRepayment: "11520.00"
                        proposedTotalRepayment: "11571.20"
                        affectedInstallments:
                          - installmentNumber: 13
                            currentDueDate: 2026-08-01
                            proposedDueDate: 2028-08-01
                            principal: "385.00"
                            interest: "35.00"
                            fees: "0.00"
                            total: "420.00"
                        previewDigest: 9c41f0b2a6d84e17
                      display:
                        deferredTotalAmount: USD 1,540.00
                        totalCostDelta: USD 51.20
                        affectedInstallmentDates: 2026-08-01, 2026-09-01, 2026-10-01, 2026-11-01
                        offerExpiryDate: 2026-08-03
                        borrowerTimeZone: America/New_York
                        offerReference: LE-OFR-6001
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
  /v1/servicing/cases/{caseId}/hardship/offers/{offerId}:
    get:
      tags:
        - Hardship
      operationId: getCaseHardshipOffer
      summary: Retrieve one hardship offer version
      description: Returns one offer version with its server-derived terms, native preview, template provenance, and
        rendered-agreement digest.
      x-permission: READ_SERVICING_CASE
      x-idempotent: false
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: caseId
          in: path
          required: true
          description: Positive numeric case identifier.
          schema:
            type: integer
            format: int64
            minimum: 1
        - name: offerId
          in: path
          required: true
          description: Stable opaque offer identifier.
          schema:
            type: string
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - offerId
                  - offerRef
                  - offerVersion
                  - deferredPaymentCount
                  - status
                  - statusReason
                  - issuedAt
                  - expiresAt
                  - approvedAt
                  - approvalPermission
                  - supersededByOfferId
                  - templateCode
                  - templateVersion
                  - renderedDigest
                  - previewDigest
                  - terms
                properties:
                  offerId:
                    type: integer
                  offerRef:
                    type: string
                  offerVersion:
                    type: integer
                  deferredPaymentCount:
                    type: integer
                  status:
                    type: string
                    description: Current normalized lifecycle state.
                  statusReason:
                    type: string
                  issuedAt:
                    type: string
                    format: date-time
                  expiresAt:
                    type: string
                    format: date-time
                  approvedAt:
                    type: string
                    format: date-time
                  approvalPermission:
                    type: string
                  supersededByOfferId:
                    type: string
                  templateCode:
                    type: string
                  templateVersion:
                    type: integer
                  renderedDigest:
                    type: string
                  previewDigest:
                    type: string
                  terms:
                    type: object
                    required:
                      - reliefType
                      - deferredPaymentCount
                      - principalForgiveness
                      - rateChange
                      - preview
                      - display
                    properties:
                      reliefType:
                        type: string
                      deferredPaymentCount:
                        type: integer
                      principalForgiveness:
                        type: boolean
                      rateChange:
                        type: boolean
                      preview:
                        type: object
                        required:
                          - sourceSystem
                          - asOf
                          - businessDate
                          - deferredInstallmentCount
                          - paymentResumptionDate
                          - currentMaturityDate
                          - proposedMaturityDate
                          - currencyCode
                          - deferredTotalAmount
                          - totalCostDelta
                          - currentTotalRepayment
                          - proposedTotalRepayment
                          - affectedInstallments
                          - previewDigest
                        properties:
                          sourceSystem:
                            type: string
                          asOf:
                            type: string
                            format: date-time
                            description: Time at which the source says the fact was true.
                          businessDate:
                            type: string
                            format: date
                          deferredInstallmentCount:
                            type: integer
                          paymentResumptionDate:
                            type: string
                            format: date
                          currentMaturityDate:
                            type: string
                            format: date
                          proposedMaturityDate:
                            type: string
                            format: date
                          currencyCode:
                            type: string
                          deferredTotalAmount:
                            type: string
                          totalCostDelta:
                            type: string
                          currentTotalRepayment:
                            type: string
                          proposedTotalRepayment:
                            type: string
                          affectedInstallments:
                            type: array
                            items:
                              type: object
                              required:
                                - installmentNumber
                                - currentDueDate
                                - proposedDueDate
                                - principal
                                - interest
                                - fees
                                - total
                              properties:
                                installmentNumber:
                                  type: integer
                                currentDueDate:
                                  type: string
                                  format: date
                                proposedDueDate:
                                  type: string
                                  format: date
                                principal:
                                  type: string
                                interest:
                                  type: string
                                fees:
                                  type: string
                                total:
                                  type: string
                          previewDigest:
                            type: string
                      display:
                        type: object
                        required:
                          - deferredTotalAmount
                          - totalCostDelta
                          - affectedInstallmentDates
                          - offerExpiryDate
                          - borrowerTimeZone
                          - offerReference
                        properties:
                          deferredTotalAmount:
                            type: string
                          totalCostDelta:
                            type: string
                          affectedInstallmentDates:
                            type: string
                          offerExpiryDate:
                            type: string
                            format: date
                          borrowerTimeZone:
                            type: string
                          offerReference:
                            type: string
              example:
                offerId: 6001
                offerRef: LE-OFR-6001
                offerVersion: 2
                deferredPaymentCount: 4
                status: READY_TO_SEND
                statusReason: null
                issuedAt: 2026-07-27T09:20:00Z
                expiresAt: 2026-08-03T09:20:00Z
                approvedAt: null
                approvalPermission: APPROVE_SERVICING_HARDSHIP_DEFERRAL_UP_TO_6
                supersededByOfferId: null
                templateCode: HARDSHIP_MEDICAL_LEAVE_AGREEMENT
                templateVersion: 1
                renderedDigest: 4e9a1c7f52d0b386
                previewDigest: 9c41f0b2a6d84e17
                terms:
                  reliefType: DEFER_SCHEDULED_INSTALLMENTS_TO_MATURITY
                  deferredPaymentCount: 4
                  principalForgiveness: false
                  rateChange: false
                  preview:
                    sourceSystem: LENDEASY_LMS
                    asOf: 2026-07-27T09:14:00Z
                    businessDate: 2026-07-27
                    deferredInstallmentCount: 4
                    paymentResumptionDate: 2026-12-01
                    currentMaturityDate: 2028-07-01
                    proposedMaturityDate: 2028-11-01
                    currencyCode: USD
                    deferredTotalAmount: "1540.00"
                    totalCostDelta: "51.20"
                    currentTotalRepayment: "11520.00"
                    proposedTotalRepayment: "11571.20"
                    affectedInstallments:
                      - installmentNumber: 13
                        currentDueDate: 2026-08-01
                        proposedDueDate: 2028-08-01
                        principal: "385.00"
                        interest: "35.00"
                        fees: "0.00"
                        total: "420.00"
                    previewDigest: 9c41f0b2a6d84e17
                  display:
                    deferredTotalAmount: USD 1,540.00
                    totalCostDelta: USD 51.20
                    affectedInstallmentDates: 2026-08-01, 2026-09-01, 2026-10-01, 2026-11-01
                    offerExpiryDate: 2026-08-03
                    borrowerTimeZone: America/New_York
                    offerReference: LE-OFR-6001
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
  /v1/servicing/cases/{caseId}/hardship/offers/{offerId}/approve-and-send:
    post:
      tags:
        - Hardship
      operationId: approveAndSendHardshipOffer
      summary: Approve an offer and send the agreement
      description: Records the one pre-send human decision on a server-generated offer and queues the rendered agreement. The
        body carries only a closed decision, a closed reason code, an optional note, a task reference, and the expected
        offer version; recipient, terms, template, and permission are all server-derived, and the loan is never
        modified.
      x-permission: APPROVE_SERVICING_HARDSHIP_DEFERRAL_UP_TO_6
      x-idempotent: true
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: caseId
          in: path
          required: true
          description: Positive numeric case identifier.
          schema:
            type: integer
            format: int64
            minimum: 1
        - name: offerId
          in: path
          required: true
          description: Stable opaque offer identifier.
          schema:
            type: string
        - name: Idempotency-Key
          in: header
          required: false
          description: Optional replay key for this logical mutation. Omission creates a fresh server-owned key for this attempt;
            blank, repeated, or longer-than-50-character values are rejected.
          schema:
            type: string
            minLength: 1
            maxLength: 50
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - caseId
                  - offerId
                  - resourceId
                  - changes
                properties:
                  caseId:
                    type: integer
                    description: Stable opaque servicing case identifier.
                  offerId:
                    type: integer
                  resourceId:
                    type: integer
                  changes:
                    type: object
                    required:
                      - offerRef
                      - decision
                      - agreementQueued
                      - offerStatus
                      - supersededOfferId
                      - loanModified
                    properties:
                      offerRef:
                        type: string
                      decision:
                        type: string
                      agreementQueued:
                        type: boolean
                      offerStatus:
                        type: string
                      supersededOfferId:
                        type: integer
                      loanModified:
                        type: boolean
              example:
                caseId: 1001
                offerId: 6001
                resourceId: 6001
                changes:
                  offerRef: LE-OFR-6001
                  decision: APPROVE_AND_SEND
                  agreementQueued: true
                  offerStatus: QUEUED
                  supersededOfferId: 6000
                  loanModified: false
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
        "409":
          $ref: "#/components/responses/Servicing409Error"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - decision
                - reasonCode
              properties:
                taskId:
                  type: integer
                decision:
                  type: string
                reasonCode:
                  type: string
                  description: Configured structured reason code.
                note:
                  type: string
                expectedOfferVersion:
                  type: integer
              example:
                taskId: 2001
                decision: APPROVE_AND_SEND
                reasonCode: WITHIN_AUTHORITY
                note: Certificate screening passed and the requested count is inside the human band.
                expectedOfferVersion: 2
            example:
              taskId: 2001
              decision: APPROVE_AND_SEND
              reasonCode: WITHIN_AUTHORITY
              note: Certificate screening passed and the requested count is inside the human band.
              expectedOfferVersion: 2
  /v1/servicing/hardship/evidence-analyses/{analysisId}:
    get:
      tags:
        - Hardship
      operationId: getHardshipEvidenceAnalysis
      summary: Retrieve an evidence analysis
      description: Returns one immutable screening analysis with its classification, closed result, reason codes, worker
        provenance, and any human decision recorded beside it. Extracted certificate fields are returned only with the
        sensitive-document permission; the verification basis always states whether AI screening or a trusted issuer
        produced the verdict.
      x-permission: READ_SERVICING_DOCUMENT
      x-idempotent: false
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: analysisId
          in: path
          required: true
          description: Stable opaque analysis identifier.
          schema:
            type: string
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - analysisId
                  - caseId
                  - documentId
                  - classification
                  - classificationConfidence
                  - result
                  - resultConfidence
                  - verificationBasis
                  - concerns
                  - reasonCodes
                  - workerCode
                  - adapterCode
                  - runtimeRelease
                  - policyVersion
                  - packetVersion
                  - humanDecision
                  - humanDecisionReason
                  - humanDecidedAt
                  - reviewTaskId
                  - screenedAt
                  - extractedFields
                properties:
                  analysisId:
                    type: integer
                  caseId:
                    type: integer
                    description: Stable opaque servicing case identifier.
                  documentId:
                    type: integer
                  classification:
                    type: string
                  classificationConfidence:
                    type: number
                  result:
                    type: string
                  resultConfidence:
                    type: number
                  verificationBasis:
                    type: string
                  concerns:
                    type: array
                    items:
                      type: string
                  reasonCodes:
                    type: array
                    items:
                      type: string
                  workerCode:
                    type: string
                  adapterCode:
                    type: string
                  runtimeRelease:
                    type: string
                  policyVersion:
                    type: string
                  packetVersion:
                    type: string
                  humanDecision:
                    type: string
                  humanDecisionReason:
                    type: string
                  humanDecidedAt:
                    type: string
                    format: date-time
                  reviewTaskId:
                    type: integer
                  screenedAt:
                    type: string
                    format: date-time
                  extractedFields:
                    type: object
                    required:
                      - borrowerName
                      - unableToWork
                      - leaveStartDate
                      - expectedReturnDate
                    properties:
                      borrowerName:
                        type: object
                        required:
                          - value
                          - confidence
                          - sourceLocation
                        properties:
                          value:
                            type: string
                          confidence:
                            type: number
                          sourceLocation:
                            type: string
                      unableToWork:
                        type: object
                        required:
                          - value
                          - confidence
                          - sourceLocation
                        properties:
                          value:
                            type: string
                          confidence:
                            type: number
                          sourceLocation:
                            type: string
                      leaveStartDate:
                        type: object
                        required:
                          - value
                          - confidence
                          - sourceLocation
                        properties:
                          value:
                            type: string
                          confidence:
                            type: number
                          sourceLocation:
                            type: string
                      expectedReturnDate:
                        type: object
                        required:
                          - value
                          - confidence
                          - sourceLocation
                        properties:
                          value:
                            type: string
                          confidence:
                            type: number
                          sourceLocation:
                            type: string
              example:
                analysisId: 8601
                caseId: 1001
                documentId: 7001
                classification: DOCTORS_MEDICAL_LEAVE_CERTIFICATE
                classificationConfidence: 0.97
                result: INCONCLUSIVE
                resultConfidence: 0.61
                verificationBasis: AI_SCREENING_ONLY
                concerns:
                  - The signature area is low resolution.
                reasonCodes:
                  - LOW_CONFIDENCE_EXTRACTION
                workerCode: DOCUMENT_EVIDENCE_AGENT
                adapterCode: DOCUMENT_EVIDENCE_V1
                runtimeRelease: runtime-2026.07
                policyVersion: policy-12
                packetVersion: packet-v1
                humanDecision: null
                humanDecisionReason: null
                humanDecidedAt: null
                reviewTaskId: 2001
                screenedAt: 2026-07-25T18:20:00Z
                extractedFields:
                  borrowerName:
                    value: Jordan Sample
                    confidence: 0.98
                    sourceLocation: page 1
                  unableToWork:
                    value: "true"
                    confidence: 0.97
                    sourceLocation: page 1
                  leaveStartDate:
                    value: 2026-07-14
                    confidence: 0.96
                    sourceLocation: page 1
                  expectedReturnDate:
                    value: 2026-08-25
                    confidence: 0.95
                    sourceLocation: page 1
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
  /v1/servicing/hardship/evidence-analyses/{analysisId}/review:
    post:
      tags:
        - Hardship
      operationId: reviewHardshipEvidenceAnalysis
      summary: Record the human evidence decision
      description: Records a closed human decision and reason beside an inconclusive or suspicious screening. The analysis
        itself is immutable; the reviewer's decision sits next to the agent's output, never over it.
      x-permission: REVIEW_SERVICING_HARDSHIP_EVIDENCE
      x-idempotent: true
      x-availability: implemented
      x-audience: client
      x-error-contract: platform-json
      security:
        - oauth2:
            - servicing:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: Opaque active LendEasy tenant-registry identifier. Supply exactly one instance; no alternate tenant
            selector is accepted.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: analysisId
          in: path
          required: true
          description: Stable opaque analysis identifier.
          schema:
            type: string
        - name: Idempotency-Key
          in: header
          required: false
          description: Optional replay key for this logical mutation. Omission creates a fresh server-owned key for this attempt;
            blank, repeated, or longer-than-50-character values are rejected.
          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:
                      - analysisId
                      - humanDecision
                    properties:
                      analysisId:
                        type: integer
                      humanDecision:
                        type: string
              example:
                resourceId: 8601
                changes:
                  analysisId: 8601
                  humanDecision: CONFIRMED
        "400":
          $ref: "#/components/responses/Servicing400Error"
        "401":
          $ref: "#/components/responses/Servicing401Error"
        "403":
          $ref: "#/components/responses/Servicing403Error"
        "404":
          $ref: "#/components/responses/Servicing404Error"
        "409":
          $ref: "#/components/responses/Servicing409Error"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - decision
                - reason
              properties:
                decision:
                  type: string
                reason:
                  type: string
                taskId:
                  type: integer
              example:
                decision: CONFIRMED
                reason: The certificate matches the stated leave dates and the signature is legible on the original.
                taskId: 2001
            example:
              decision: CONFIRMED
              reason: The certificate matches the stated leave dates and the signature is legible on the original.
              taskId: 2001
components:
  securitySchemes:
    oauth2:
      type: oauth2
      description: OAuth 2.0 client credentials. The issued token identifies the client and granted scopes; ordinary API calls
        select one authorized tenant with LendEasy-Tenant.
      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.
    gatewaySignature:
      type: apiKey
      in: header
      name: X-LendEasy-Gateway-Signature
      description: Pinned channel-gateway signature over the exact request bytes. Ordinary client authentication is not accepted.
    voiceTaskToken:
      type: apiKey
      in: header
      name: X-LendEasy-Voice-Task-Token
      description: Short-lived task token bound to one voice dispatch and its callback audience.
    uploadLinkToken:
      type: apiKey
      in: header
      name: LendEasy-Upload-Link
      description: Single-use emailed link secret exchanged once for a bounded borrower upload session.
    uploadSession:
      type: apiKey
      in: header
      name: LendEasy-Upload-Session
      description: Short-lived borrower upload session token bound to one case, customer, and evidence purpose.
  schemas:
    PlatformError:
      type: object
      required:
        - developerMessage
        - httpStatusCode
        - defaultUserMessage
        - userMessageGlobalisationCode
        - errors
      properties:
        developerMessage:
          type: string
        httpStatusCode:
          type: string
        defaultUserMessage:
          type: string
        userMessageGlobalisationCode:
          type: string
        errors:
          type: array
          items:
            type: object
    ConnectorError:
      type: object
      required:
        - error
      properties:
        error:
          type: string
          description: Safe connector rejection reason.
  responses:
    Servicing400Error:
      description: Malformed request, unknown field/query parameter, invalid tenant or idempotency header, or field-level
        validation failure.
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/PlatformError"
          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: []
    Servicing401Error:
      description: Missing or invalid credentials.
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/PlatformError"
          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: []
    Servicing403Error:
      description: Caller lacks the required permission, required case context, or valid actor-to-case relationship.
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/PlatformError"
          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: []
    Servicing404Error:
      description: Resource not found or not visible to the caller.
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/PlatformError"
          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: []
    Servicing409Error:
      description: State conflict, an idempotent request still in flight (includes Retry-After), or a single-entry conflict.
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/PlatformError"
          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: []
    Connector400Error:
      description: Malformed or unsupported callback body.
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/ConnectorError"
          example:
            error: The callback body is invalid.
    Connector401Error:
      description: Missing, invalid, expired, or differently bound connector authority.
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/ConnectorError"
          example:
            error: Invalid or missing connector authority.
    Connector404Error:
      description: No visible dispatch exists.
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/ConnectorError"
          example:
            error: No visible voice dispatch exists.
    Connector409Error:
      description: The callback conflicts with current dispatch state or an already accepted result.
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/ConnectorError"
          example:
            error: The callback conflicts with current dispatch state.
