Quickstart
Make a production-shaped Sandbox call in five minutes with the LendEasy Lending Core and the Servicing Workspace that runs natively on it.
LendEasy is adoptable in pieces, and which piece you start with decides what your first call looks like. Everything below runs against Sandbox, which holds the same contract as Production — identical paths, identical payload shapes, with simulated rails and fictional data standing in for real money. That is the point of starting here: a call you got working against a mock of your own has proved nothing about the contract you will ship on.
One contract, three ways to adopt it
LendEasy exposes one public contract: the LendEasy Lending Core and the Servicing Workspace that runs natively on it — adoptable together or separately:
- Exchange Sandbox credentialsone token, one environment, one tenant — every path starts here
- Full platformcreate a customer, preview a schedule, originate a loan — new programs and core migrations
- Servicing Workspaceopen a case on the servicing API — cases, work, interactions, controls, evidence
- Bring your own corebind the system of record you already run, publish capabilities, map identities
The examples below use fictional Sandbox data from the example product portfolio. Monetary representations follow each operation schema: current servicing money fields use an { amount, currency } object, while Lending Core operations use their declared string or numeric form.
1. The secret never leaves your backend
Credentials are isolated by environment. Exchange the Sandbox client ID and secret from a trusted backend. A secret shipped into a browser bundle or a mobile binary has been published, and rotating it is the only way to take it back.
export BASE=https://sandbox.api.lendeasy.ai
export CLIENT_ID=your_sandbox_client_id
export CLIENT_SECRET=your_sandbox_client_secret
export TOKEN=$(curl --silent https://auth.lendeasy.ai/oauth2/token \
-u "$CLIENT_ID:$CLIENT_SECRET" \
-H "Content-Type: application/x-www-form-urlencoded" \
--data-urlencode "grant_type=client_credentials" \
--data-urlencode "scope=lending:read lending:write servicing:read servicing:write" \
| jq -r .access_token)
Tokens are short-lived and environment-specific. Cache a token until shortly before its expires_in window ends; a client that mints a fresh one for every call puts the token endpoint in front of every other request it makes, so one slow moment there stalls all of them. Every API call also names its tenant with the LendEasy-Tenant header — the Sandbox examples use demo-lender.
2A. Full platform: create the customer, then read it back
Create the customer with its first residence and contact detail in one request. The Idempotency-Key is optional; sending one lets a retry return the original result instead of creating a second record.
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 this command receipt and nothing else, so a client that treats the create response as the record will be missing every field it did not send. Read GET /v1/customers/412 for the whole customer record — the profile plus its current addresses, masked phone numbers and emails, consents, and masked identifiers. Keep the customer ID (it serializes as the string "412" on reads) as the relationship key used by loans, instruments, and restrictions, and use externalId to correlate with your own application or CRM. Next, follow Originate a loan.
2B. Servicing Workspace: open a case from a signal
The implemented Servicing Workspace uses numeric record IDs and stable string references. Create a collections matter from an authoritative signal:
curl -X POST "$BASE/v1/servicing/cases" \
-H "Authorization: Bearer $TOKEN" \
-H "LendEasy-Tenant: demo-lender" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: collections-event-789" \
-d '{
"customerRef": "412",
"caseTypeCode": "COLLECTIONS",
"reasonCode": "DELINQUENCY_SIGNAL",
"priority": "HIGH",
"loanRefs": ["7204"],
"sourceType": "LMS_EVENT",
"sourceRef": "event-789"
}'
{
"caseId": 1001,
"externalCaseRef": "LE-CASE-1001",
"status": "OPEN",
"deduplicated": false,
"resourceId": 1001
}
Continue with API availability for the current task, interaction, governed-operation, and evidence routes.
Six rules worth checking before you build
They hold across every call you will make, and each is cheap to confirm now and expensive to discover halfway through a workflow:
- every ordinary implemented call carries the
LendEasy-Tenantheader;Idempotency-Keyis optional but recommended on current Lending Core and implemented servicing mutations (1–50 characters), and a replay returns the original result withx-served-from-cache: true; - every money amount carries an ISO 4217 currency — decimal strings on LendEasy-owned resources, decimal numbers on native loan routes;
- every effective business date is distinct from its processing timestamp;
- Lending Core IDs are numeric (customer
412, loan7204;customerIdandloanRefserialize as strings); current Servicing Workspace record IDs are also numeric, while stable external references such asexternalCaseRef,customerRef,loanRef, andeffectRefremain strings; - a
409is resolved by reading current state — or by waitingRetry-Afterwhen the same request is still in flight — never by blind retry; - a governed command can park under maker-checker, where a different checker approves it before it executes.