Customer identifiers
A government ID is supplied in full exactly once and never echoed back — ordinary reads see a mask, and the full value comes only from an audited route that records who looked.
A single “verified customer” flag is the tidiest thing you can build and the least defensible thing you can rely on: it makes every later decision trust whichever check behind it was weakest. So LendEasy does not collapse identity into one boolean. A customer is the party; an identifier is one claim about that party, and names, government numbers, and your own correlation key carry different security and verification semantics.
Three identifier classes, three exposure rules
| Class | Example | Stored on customer record | Ordinary response |
|---|---|---|---|
| Numeric LendEasy ID | customerId 412 |
Generated relationship key | Full value (serialized as "412") |
| Your external ID | crm-person-81042 |
Caller-controlled correlation key on the profile | Full caller-controlled value |
| Government identifier | U.S. SSN, EIN, DRIVER_LICENSE, PASSPORT |
Complete value, normalized at write time | Type, mask, lifecycle, verification state |
INDIVIDUAL customers use SSN, DRIVER_LICENSE, or PASSPORT; CORPORATE customers use EIN. A name, email address, or phone number makes a poor relationship key: two people in one household share an email, a married borrower changes a surname, and a phone number is reassigned to a stranger within months. Keyed that way, a portfolio quietly merges two customers into one and splits a third in half.
Supplied once, and never echoed back
Supply the complete value exactly once, at write time. LendEasy normalizes it: an SSN or EIN is reduced to nine digits regardless of punctuation.
Punctuation goes in; nine digits are stored
curl -X POST "$BASE/v1/customers/412/identifiers" \
-H "Authorization: Bearer $TOKEN" \
-H "LendEasy-Tenant: demo-lender" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: maya-ssn-v1" \
-d '{
"identifierType": "SSN",
"value": "601-11-4821"
}'
{ "resourceId": 66 }
Requires UPDATE_LMS_CUSTOMER_IDENTIFIER. Normalizing at write time is what makes an exact lookup work however the caller typed it, so the same person is not filed twice under two punctuations. The customer read shows:
{
"identifierId": 66,
"identifierType": "SSN",
"maskedDisplay": "•••-••-4821",
"verificationState": "UNVERIFIED",
"status": "ACTIVE"
}
Verification is set by trusted integrations
Verification belongs to one identifier. Maya may have a verified SSN, a verified email, and an unverified residence at the same time. A decision names which facts and assurance level it requires instead of trusting a customer-wide boolean.
Two audited routes touch complete values
Both require READ_LMS_CUSTOMER and READ_LMS_CUSTOMER_SENSITIVE together:
GET /v1/customers/{customerId}/sensitivereturns complete identifier values alongside raw contact values and consent evidence.POST /v1/customers/lookupfinds customers whose current identifier exactly equals the supplied value. A POST body keeps the value out of URLs and logs; the route accepts noIdempotency-Keyand answers with masked summaries only.
curl -X POST "$BASE/v1/customers/lookup" \
-H "Authorization: Bearer $TOKEN" \
-H "LendEasy-Tenant: demo-lender" \
-H "Content-Type: application/json" \
-d '{
"identifierType": "SSN",
"value": "601114821"
}'
{
"items": [{
"customerId": "412",
"status": "ACTIVE",
"customerType": "INDIVIDUAL",
"displayName": "Maya Chen",
"lastModifiedAt": "2026-09-15T14:22:08Z"
}]
}
An empty result never reveals whether a hidden match exists. A lookup that distinguished “no such customer” from “a customer you may not see” would be an oracle: a caller could confirm somebody’s identifier one probe at a time without ever being allowed to read it.
A wrong value is replaced, not edited
identifierType is immutable. PUT /v1/customers/{customerId}/identifiers/{identifierId} merge-updates the record—attaching an evidenceRef, for example—but a wrong number is corrected by removing the identifier and adding the right one. Editing it in place would leave every decision made on the old value looking as though it had been made on the new one. DELETE is a bodyless soft removal: the identifier leaves the customer record read, and its masked history is retained in the customer ledger for authorized audit views.
externalId, a note, a form field, an idempotency key, a URL, or an error message. Those values are designed to be operationally visible; the identifier routes are the only place complete values belong.