LendEasy/DocsLMS + Servicing·v1
Start integrating
GuidesServicing PlaneServicing reports

Servicing reports

Read bounded workforce, collections, interaction, compliance, AI-quality, and drift projections with drill-through to the base collections, plus the curated investor reporting pack.

Servicing reports are bounded projections, not an analytics warehouse. Each one answers a specific operating question, echoes the query it actually applied, and points back at the canonical collection so a number can always be opened as work.

The six operational reports

Report Route Answers
Workforce GET /v1/servicing/reports/workforce Where is work piling up, and who has capacity?
Collections GET /v1/servicing/reports/collections Which delinquent matters are contactable, and when?
Interaction exceptions GET /v1/servicing/reports/interactions/exceptions Which channel work was missed, unmatched, or failed?
Compliance GET /v1/servicing/reports/compliance What did policy decide, under which rules and regimes?
AI quality GET /v1/servicing/reports/ai-quality How grounded and how reviewed is AI output?
Reconciliation GET /v1/servicing/reports/reconciliation Where has servicing state drifted from the LMS?
Promise & allocation GET /v1/servicing/reports/promise-allocation Are promises being kept, and is work reaching the people who can keep them?

All six take READ_SERVICING_REPORTS, accept exact structured filters plus limit/offset and sort/order, and return the same outer shape:

{
  "asOf": "2027-05-05T18:30:00Z",
  "effectiveQuery": { "limit": 50, "offset": 0 },
  "rows": [],
  "returnedCount": 0,
  "hasMore": false
}

effectiveQuery echoes what the server actually applied after defaults and caps. Read it before trusting a total — a report page is a bounded slice, and returnedCount counts the rows in this response, not the population behind it.

Drill-through, not a dead end

The workforce report aggregates by QUEUE or WORKER and gives each row a canonical link back into the base collection:

{
  "dimension": "QUEUE",
  "summary": {
    "openTaskCount": 18,
    "activeTaskCount": 7,
    "staleAcceptedTaskCount": 1,
    "overdueTaskCount": 2,
    "slaBreachedTaskCount": 1,
    "openCaseCount": 42,
    "availableWorkerCapacity": 21
  },
  "rows": [
    {
      "queueCode": "COLLECTIONS",
      "openTaskCount": 18,
      "overdueTaskCount": 2,
      "oldestTaskAgeMinutes": 91,
      "eligibleWorkerCapacity": 28,
      "availableWorkerCount": 4,
      "drillThrough": "/v1/servicing/tasks?queueCode=COLLECTIONS"
    }
  ]
}

drillThrough is the report’s contract with the workspace: the aggregate and the list it opens are the same query. staleAccepted=true isolates accepted work that has stopped moving — the case a throughput average hides.

Collections and contact timing

The collections report joins current LMS financial facts to servicing work state, so a row carries both the money and the permission to act on it:

{
  "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": "2027-05-04T21:04:00Z",
  "nextPermittedContactAt": "2027-05-06T15:00:00Z",
  "protectiveStateActive": false,
  "contactBlocked": false
}

financialFactsSource names where the balance came from; the servicing plane does not recompute delinquency. nextPermittedContactAt and remainingContactCapacity are planning aids from the contact budget, not authorizations — the owning operation still runs its own execution-time check immediately before contact, and can block work this report showed as permitted.

Compliance, AI quality, and drift

The compliance report exposes decision outcomes with their rule and regime detail, filterable by outcome, hardStop, regime, ruleCode, channel, and proposedAction:

{
  "decisionId": 6117,
  "proposedAction": "OUTBOUND_CONTACT",
  "channel": "PHONE",
  "outcome": "ALLOWED",
  "hardStop": false,
  "rules": [{ "ruleCode": "CONTACT_WINDOW_CA", "regime": "REG_F", "outcome": "ALLOWED" }]
}

The AI-quality report projects retained output, grounding, runtime, and review state together — session, worker and adapter codes, autonomyLevel, runtimeVersion, policyVersion, workPacketVersion, confidence, groundingStatus, and the reviewer and review time. Because runtime and policy versions are rows rather than metadata, a quality regression can be attributed to the version that caused it instead of being averaged away.

The reconciliation report returns current servicing-to-LMS drift with its classification, priority, and the review task opened for it:

{
  "driftId": 81,
  "driftType": "EXPECTED_STATE_MISMATCH",
  "objectType": "AUTOPAY",
  "objectRef": "456",
  "customerRef": "123",
  "status": "OPEN",
  "priority": "HIGH",
  "reviewTaskId": 2005,
  "detectedAt": "2027-05-05T18:30:00Z"
}

This is the servicing-plane view of drift. Money-movement exceptions between provider events, intents, and the ledger stay in the Lending Core catalog — see Reconciliation & drift.

The investor reporting pack

Two routes serve a curated 18-report pack: GET /v1/servicing/reports/investor lists the catalog, and GET /v1/servicing/reports/investor/{reportKey} returns one report. Both accept READ_REPORT or READ_SERVICING_REPORTS.

Every response carries its provenance:

{
  "provenance": {
    "label": "Reporting snapshot",
    "loadKey": "INVESTOR_V1:2027-05-05",
    "sourceWatermark": "portfolio-v1:2027-05-05",
    "generationMode": "SNAPSHOT_LOAD",
    "nonAuthoritative": true
  }
}

The pack is a snapshot load. It never reads live servicing or ledger tables, and nonAuthoritative: true is a contract, not a disclaimer — reconcile against the authoritative source before publishing a figure externally.

A report renders as headline metrics, insights, a trend, a breakdown, a supporting table, and a methodology note. Metrics declare their own format (number, percent, currency) and tone, and delta/deltaLabel keys are omitted when no comparison period was supplied rather than returned as zero. The reportKey must come from the catalog; an arbitrary key is rejected.

Read methodology before comparing two figures. In the collections pack, for example, promise kept-rate is count-based while dollar kept-rate is value-based, and promise dollars are never counted as collected until the cash is realized.
These projections are bounded reads for operating and oversight. They are not an export path for bulk personal data, and no report returns sensitive content that the caller could not read through the owning resource.
Unified search across guides, recipes & the API referenceEsc