Notes
A note carries the human context no structured field can hold, kept as immutable revisions that can be corrected, linked, and—when free text goes wrong—permanently redacted.
Every servicing operation accumulates the sentence that explains everything. A note is where that sentence lives, so it does not end up wedged into an amount field or lost in somebody’s mailbox.
A note carries
- Why an exception was granted, in the words used
- What the borrower actually said on the call
- What the next worker needs before they dial
A note enforces nothing
- “Payment received” is not a payment fact
- “Do not call” stops nothing; nothing reads it first
- “Approved” cannot stand in for an approval record
- It grants no consent, verifies nobody, moves no balance
Decide sensitivity before you submit
curl -X POST "$BASE/v1/loans/7204/notes" \
-H "Authorization: Bearer $TOKEN" \
-H "LendEasy-Tenant: demo-lender" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: note-harbor-payoff-delivery" \
-d '{
"body": "Maya requested email delivery for the payoff figure.",
"sensitive": false,
"pinned": false
}'
{ "resourceId": 802 }
Requires CREATE_LMS_NOTE; the same route family exists at POST /v1/customers/{customerId}/notes. The actor and time come from authenticated execution context rather than caller-supplied prose—a note that says who wrote it because somebody typed a name is a story, not evidence, and it is the notes on the difficult accounts that get read back in a dispute. A body can hold up to 20,000 characters, and marking a note sensitive requires the sensitive read permission—decide before submission, because restricted legal, medical, dispute, or vulnerability context must not spend even a short interval as ordinary text.
Markers first, bodies one at a time
GET /v1/customers/{customerId}/notes and GET /v1/loans/{loanId}/notes return markers only—pinned first, newest first:
{
"items": [{
"noteId": 802,
"noteRef": "note_9c1d3e5f7a9b1c3d5e7f",
"status": "ACTIVE",
"sensitive": false,
"pinned": false,
"flagged": false,
"redactionState": "NONE"
}]
}
Bodies are read one note at a time via GET /v1/notes/{noteId} (READ_LMS_NOTE). A sensitive body additionally requires the sensitive read permission, so a marker list never leaks restricted text to a caller who can only see that a note exists.
| Attribute | Meaning |
|---|---|
sensitive |
Body readable only with the additional sensitive read permission. |
pinned |
Surfaces first in lists for must-read context. |
flagged |
Marks the note for follow-up or review. |
status |
ACTIVE or ARCHIVED. |
redactionState |
NONE, or evidence that content was permanently redacted. |
There is deliberately no category field. A taxonomy becomes a place where things are filed rather than a place where things are read, and the note that mattered ends up under a heading nobody opened; links and flags put it in front of the next worker instead.
Revise; never rewrite
If Maya actually requested secure message rather than email, revise the note. PUT /v1/notes/{noteId} (UPDATE_LMS_NOTE) appends a new immutable revision with an optional changeReason; the original revision is never edited or deleted.
curl -X PUT "$BASE/v1/notes/802" \
-H "Authorization: Bearer $TOKEN" \
-H "LendEasy-Tenant: demo-lender" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: revise-note-802-channel" \
-d '{
"body": "Maya requested secure-message delivery for the payoff figure.",
"changeReason": "Channel corrected."
}'
GET /v1/notes/{noteId} always returns the current revision’s body; GET /v1/notes/{noteId}/history returns revision metadata newest first—revision number, type, and reasons—never the bodies themselves. The history read answers what changed and why, not what every superseded draft said, so it cannot become a second unrestricted copy of content that sensitivity rules and redaction were applied to.
Links deactivate, redaction destroys
POST /v1/notes/{noteId}/linksattaches the note to another customer or loan ({ "targetType": "CUSTOMER", "targetRef": "412" });POST /v1/notes/{noteId}/links/{linkId}/removedeactivates one link while retaining the row and its removal.POST /v1/notes/{noteId}/archive(ARCHIVE_LMS_NOTE) takes no body, is idempotent, and retains all revisions.POST /v1/notes/{noteId}/redact(REDACT_LMS_NOTE) takes a requiredredactionReason, appends a redaction revision, and permanently replaces the content: every read thereafter returns a placeholder, redacted notes cannot be revised, and redaction cannot be undone. The reason survives because the fact that content was destroyed is itself part of the record—a note that simply vanished would look like one that had never been written.
Send the consequence somewhere that enforces it
A note saying “do not call” belongs in the cease-contact workflow. Use Forms for schema-validated intake, Interactions for customer communications, and Restrictions for enforceable stops.