Onboard a borrower
Create a customer with their address and contact details, add a government ID that is stored masked, record a consent, and read the whole record back.
This recipe creates Maya Chen, the borrower used by the Harbor Personal Loan. Use synthetic data in Sandbox.
- Create the customerprofile, address, contact detail
- Attach the identifiersupplied once, masked thereafter
- Record a consentfrom the approved list, with its evidence
- Read the masked recordthe only current-state read
Create the customer
IdempotentThe 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 short command receipt naming the resource they touched; read the record back for its current 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.
Attach the government identifier
Supplied onceThe complete value is stored normalized — SSN and EIN normalize to nine digits — and masked on every ordinary read. 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.
Record a consent from a fixed list
Evidence requiredConsents come from a fixed list—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.
Read the masked record
The customer read covers addresses, contact details, 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" }]
}If your own core owns the borrower, do not recreate this record. Follow Bring your own system of record and map the core identity to a LendEasy servicing identity.