LendEasy/Docs
Get API keys
GuidesBorrowers & CustomersCustomer identities

Customer identifiers

Attach government identifiers to a stable customer by supplying the complete value once, expose only normalized masks on ordinary reads, and reveal complete values through audited sensitive routes.

A customer is the party; an identifier is one claim about that party. Names, government numbers, and your own correlation key have different security and verification semantics, so LendEasy does not collapse them into one “verified customer” flag.

Identifier classes

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. Do not use a name, email address, or phone number as a relationship key. They change, may be shared, and are sensitive search inputs.

The masking boundary

Supply the complete value exactly once, at write time. LendEasy normalizes it—an SSN or EIN is reduced to nine digits regardless of punctuation—and every ordinary read returns only the type, a masked display, and lifecycle state. Complete values never appear in command audit records, history events, or logs.

collection UI ── complete value ──► POST /v1/customers/{customerId}/identifiers
aggregate read ─► identifierId + identifierType + maskedDisplay + verificationState
sensitive read ─► complete value (both read permissions; audited; never cached)

This boundary prevents a broad customer read, report, log, or support tool from becoming a secret-extraction path, while still letting authorized staff retrieve the value when a regulator or provider requires it.

Add an identifier

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. The value is stored as 601114821 and shows up on the aggregate read as:

{
  "identifierId": 66,
  "identifierType": "SSN",
  "maskedDisplay": "•••-••-4821",
  "verificationState": "UNVERIFIED",
  "status": "ACTIVE"
}

Notice that the complete value is not echoed back—not in the command envelope, not in the aggregate, not in history.

Verification is set by trusted integrations

There is no public verify route. Identity-verification providers write verification state through trusted integrations; API callers can attach an evidence reference but cannot assert verification.

Verification belongs to one identifier. Maya may have a verified SSN, a verified email contact point, 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.

Reveal and exact lookup

Two audited routes work with complete values, and both require READ_LMS_CUSTOMER and READ_LMS_CUSTOMER_SENSITIVE together:

  • GET /v1/customers/{customerId}/sensitive returns complete identifier values alongside raw contact values and consent evidence. Every call is audited and the response is never cached.
  • POST /v1/customers/lookup finds customers whose current identifier exactly equals the supplied value. A POST body keeps the value out of URLs and logs; the route accepts no Idempotency-Key and 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.

Corrections and removal

identifierType is immutable. PUT /v1/customers/{customerId}/identifiers/{identifierId} merge-updates the record—for example attaching an evidenceRef—and a wrong value is corrected by removing the identifier and adding the right one, so historical decisions remain explainable. DELETE is a bodyless soft removal: the identifier leaves the aggregate read, and its masked history is retained in the customer ledger for authorized audit views.

Never put a government identifier in 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.
Unified search across guides, recipes & the API referenceEsc