LendEasy/Docs
Get API keys
RecipesOnboardingOnboard a borrower

Onboard a borrower

Create a durable customer aggregate with its initial address and contact point, attach a normalized government identifier, record a consent from the closed catalog, and read the masked record back.

Time
~6 min
Surface
LMS API
Steps
4
Gate
PII · consent evidence
EndpointsPOST /v1/customersPOST /v1/customers/{customerId}/identifiersPOST /v1/customers/{customerId}/consentsGET /v1/customers/{customerId}

This recipe creates Maya Chen, the borrower used by the Harbor Personal Loan. Use synthetic data in Sandbox.

1

Create the customer aggregate

Idempotent
POST/v1/customers

Create the profile, residence, and email contact point in one request. The profile is a closed union—customerType is INDIVIDUAL or CORPORATE and is immutable after creation. externalId is your correlation key; customerId is LendEasy’s stable relationship key.

curl -X POST "$BASE/v1/customers" \
  -H "Authorization: Bearer $TOKEN" \
  -H "LendEasy-Tenant: demo-lender" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: customer-crm-person-81042" \
  -d '{
    "profile": {
      "customerType": "INDIVIDUAL",
      "firstName": "Maya",
      "lastName": "Chen",
      "dateOfBirth": "1991-11-04",
      "externalId": "crm-person-81042"
    },
    "addresses": [{
      "addressType": "PRIMARY_RESIDENCE",
      "line1": "428 Alder Way",
      "city": "Sacramento",
      "stateCode": "US-CA",
      "postalCode": "95814",
      "country": "US",
      "isPrimary": true
    }],
    "contactPoints": [{
      "contactType": "EMAIL",
      "value": "maya.chen@example.test",
      "isPrimary": true
    }]
  }'
{ "resourceId": 412 }

Mutations return a command envelope naming the resource they touched; read the aggregate back for canonical state. A timeout after submission is safe to retry with the same Idempotency-Key: a completed request replays the original result with x-served-from-cache: true, and an in-flight duplicate returns 409 with Retry-After.

2

Attach the government identifier

Supplied once
POST/v1/customers/412/identifiers

The complete value is supplied once, stored normalized—SSN and EIN normalize to nine digits—and masked on every ordinary read afterward. There is no verification call to make: verification state is set only by trusted integrations.

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: identifier-maya-ssn" \
  -d '{ "identifierType": "SSN", "value": "601-11-4821" }'
{ "resourceId": 66 }

The complete value never appears again outside the audited GET /v1/customers/412/sensitive read, which requires the additional sensitive-read permission.

3

Record a consent from the closed catalog

Evidence required
POST/v1/customers/412/consents

An email address says where Maya can be reached; it does not say how she may be contacted. Consents come from a closed catalog—ELECTRONIC_COMMUNICATION, AUTODIALED_CALL, ARTIFICIAL_VOICE, UNUSUAL_TIME—each recorded with its capture time, capture method, and optional evidence reference.

curl -X POST "$BASE/v1/customers/412/consents" \
  -H "Authorization: Bearer $TOKEN" \
  -H "LendEasy-Tenant: demo-lender" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: consent-maya-autodialed" \
  -d '{
    "consentType": "AUTODIALED_CALL",
    "capturedAt": "2026-08-01T17:05:00Z",
    "captureMethod": "BORROWER_PORTAL",
    "evidenceRef": "evd_CONSENT_41"
  }'
{ "resourceId": 71 }

Revocation is its own immutable event—POST /v1/customers/412/consents/71/revoke with no body—so the original grant and its evidence are never rewritten.

4

Read the masked aggregate

GET/v1/customers/412

The aggregate is the only current-state read for addresses, contact points, identifiers, and consents—there are no child GET routes. Ordinary reads mask contact and identifier values; complete values require the separately permissioned, audited /sensitive read.

curl "$BASE/v1/customers/412" \
  -H "Authorization: Bearer $TOKEN" \
  -H "LendEasy-Tenant: demo-lender"
{
  "customerId": "412",
  "status": "ACTIVE",
  "profile": { "customerType": "INDIVIDUAL", "firstName": "Maya", "lastName": "Chen", "dateOfBirth": "1991-11-04", "externalId": "crm-person-81042" },
  "addresses": [{ "addressId": 311, "addressType": "PRIMARY_RESIDENCE", "line1": "428 Alder Way", "city": "Sacramento", "stateCode": "US-CA", "postalCode": "95814", "country": "US", "isPrimary": true, "status": "ACTIVE" }],
  "contactPoints": [{ "contactPointId": 512, "contactType": "EMAIL", "maskedDisplay": "m•••@example.test", "isPrimary": true, "status": "UNVERIFIED" }],
  "identifiers": [{ "identifierId": 66, "identifierType": "SSN", "maskedDisplay": "•••-••-4821", "verificationState": "UNVERIFIED", "status": "ACTIVE" }],
  "consents": [{ "consentId": 71, "consentType": "AUTODIALED_CALL", "status": "GRANTED", "capturedAt": "2026-08-01T17:05:00Z", "captureMethod": "BORROWER_PORTAL" }]
}
Onboarded. Maya now has a stable aggregate, a normalized identifier, and an evidence-backed consent. Add a verified instrument next; no loan or money movement has been created yet.

If your own core owns the borrower, do not recreate this aggregate. Follow Bring your own system of record and map the core identity to a LendEasy servicing identity.

Unified search across guides, recipes & the API referenceEsc