LendEasy/DocsLMS + Servicing·v1
Start integrating
Guides›Borrowers & Customers›Documents

Documents

A document is evidence, so its bytes never change, its content is unreachable until a scan clears it, and its checksum is re-verified on the way out.

A document is what somebody will want to look at when the file is being argued over—a pay statement, an identity card, a signed agreement. Everything about how the Lending Core stores one follows from that: bytes that cannot be swapped, content that is unreachable until a scan has cleared it, and a checksum re-checked on the way out. Evidence that can be quietly replaced is worse than no evidence, because it will be believed.

An unlinked document cannot exist

POST /v1/documents (CREATE_LMS_DOCUMENT) is a single multipart request with two parts: a JSON metadata part and the file part. At least one CUSTOMER or LOAN link is required at upload, so nothing lands in a general pile that no borrower or loan can be traced to. The server derives the checksum and content type from the bytes; caller-asserted values cannot disagree with the file, which is what stops an executable arriving labeled as a PDF and being served back to a reviewer as one.

curl -X POST "$BASE/v1/documents" \
  -H "Authorization: Bearer $TOKEN" \
  -H "LendEasy-Tenant: demo-lender" \
  -H "Idempotency-Key: harbor-pay-statement-april" \
  -F 'metadata={"title":"Pay statement — April","documentType":"INCOME_EVIDENCE","sensitive":false,"links":[{"targetType":"LOAN","targetRef":"7204"}]};type=application/json' \
  -F 'file=@pay-statement-april.pdf;type=application/pdf'
{ "resourceId": 1204 }

documentType is an UPPER_SNAKE classification code. The optional sensitive flag restricts reads to callers holding the additional sensitive read permission—and setting it requires that same permission, so a caller cannot restrict content they could not themselves read. An optional supersedesDocumentId records that this upload replaces an earlier document, because content is immutable: a corrected file is always a new document. The superseded copy is the one the borrower actually received, and overwriting it in place would leave a dispute about what they were sent with nothing to consult.

Nothing is downloadable until it is clean

Only CLEAN-scanned content can be downloaded. Rejected content never becomes reachable—the record remains as evidence that the upload happened, but the bytes are gone.

The checksum is re-verified on the way out

GET /v1/documents/{documentId} (READ_LMS_DOCUMENT) returns metadata, scan status, checksum, and active links; sensitive documents additionally require the sensitive read permission.

{
  "documentId": 1204,
  "documentRef": "doc_4f2a9c1b8d3e5a7c9b1d",
  "documentType": "INCOME_EVIDENCE",
  "title": "Pay statement — April",
  "origin": "STAFF_UPLOAD",
  "originalFileName": "pay-statement-april.pdf",
  "contentType": "application/pdf",
  "contentLength": 184220,
  "checksumSha256": "2d8c1f0e5b7a4c6d8e0f2a4b6c8d0e1f3a5b7c9d1e3f5a7b9c1d3e5f7a9b188a",
  "scanStatus": "CLEAN",
  "status": "ACTIVE",
  "sensitive": false,
  "createdAt": "2027-05-01T10:40:00Z",
  "links": [{ "linkId": 61, "targetType": "LOAN", "targetRef": "7204", "active": true }]
}

GET /v1/documents/{documentId}/content streams the original bytes as an attachment after re-verifying the stored checksum, so storage that has decayed under a document is caught at the moment somebody asks for it rather than handed over as though it were intact. The response is never cached.

GET /v1/customers/{customerId}/documents and GET /v1/loans/{loanId}/documents list documents actively linked to that target, newest first. The loan listing includes system-generated documents: every completed statement is also a loan-linked document, so the statement PDF a borrower received is discoverable alongside uploaded evidence. See Statements.

Metadata changes; content never does

  • PUT /v1/documents/{documentId} (UPDATE_LMS_DOCUMENT) updates title, description, or the sensitive flag and returns the command response with the changed fields. Content, origin, and checksum are immutable.
  • POST /v1/documents/{documentId}/links adds a link to another customer or loan ({ "targetType": "CUSTOMER", "targetRef": "412" }); POST /v1/documents/{documentId}/links/{linkId}/remove deactivates one link with an optional reasonCode, retaining the link row and its removal.
  • POST /v1/documents/{documentId}/archive (ARCHIVE_LMS_DOCUMENT) takes no body and is idempotent; content and history are retained. A document’s status is ACTIVE, ARCHIVED, or—once retention policy disposes of it—DISPOSED.
  • GET /v1/documents/{documentId}/history returns the document’s change events—creation, metadata updates, link changes, archive—newest first. Document activity also appears in the linked customer’s ledger under the DOCUMENT category; see Customer lifecycle.

Case evidence lives in the servicing workspace

These routes are the Lending Core’s document store, and they hold what belongs to a borrower and a loan. Servicing cases have their own evidence pipeline under /v1/servicing/...—registration, short-lived upload targets, structured review, and retention holds—documented in Documents & secure upload. Keeping the two apart is what lets a case’s retention hold expire without touching the signed agreement the loan still needs.

A malware scan is not a secrets check. It screens for malicious files and passes a spreadsheet of card numbers without comment, so a file uploaded on the strength of “the scan will catch it” lands intact in a store many people can read. Use the sensitive flag for restricted evidence and keep credentials and card data out of documents entirely.
Unified search across guides, recipes & the API referenceEsc