Filtering & sorting
Every list endpoint exposes a closed, documented filter set, and anything outside it is refused rather than quietly dropped.
Each list endpoint exposes a closed, documented filter set. An unknown parameter — filter, sort, or paging — returns 400; it is never silently ignored. That refusal is the feature: a dropped filter returns a larger, wrong answer that looks exactly like a right one, and nothing downstream can tell that the narrowing you asked for never happened. There is no generic query language across resources.
- statusdocumented, repeatable
- raildocumented enum
- sortnot documented here
Each resource’s filter set is its own
Three representative sets — what a resource accepts is its own property, not a pattern for the next one:
| Endpoint | Documented filters |
|---|---|
GET /v1/loans/{loanId}/payments |
status (repeatable), source, rail, plus limit/offset. |
GET /v1/loans |
externalId, accountNo, clientId, status, plus offset/limit/orderBy/sortOrder. |
GET /v1/external-parties |
partyType, verificationState, active, and search — a case-insensitive substring match on display name. |
Filter values are documented enums and identifiers, not free text:
curl "$BASE/v1/loans/7204/payments?status=POSTED&rail=ACH&limit=50" \
-H "Authorization: Bearer $TOKEN" \
-H "LendEasy-Tenant: demo-lender"
An ID filter stays tenant-scoped and permission-aware: a valid ID outside the caller’s visibility never becomes a cross-tenant probe.
Half-open windows compose without double-counting
The endpoint declares which time field a filter uses and its boundary rule. Customer history takes a half-open instant window — occurredFrom inclusive, occurredTo exclusive:
occurredFrom = 2026-09-01T00:00:00-07:00 (inclusive)
occurredTo = 2026-10-01T00:00:00-07:00 (exclusive)
Consecutive months then meet at midnight with nothing landing in both. Journal entries instead take inclusive fromDate/toDate business dates. Send RFC 3339 offsets for instants and ISO YYYY-MM-DD for business dates, and read each endpoint’s boundary rule — carrying the half-open habit onto an inclusive endpoint drops the last day of every window, and carrying the inclusive habit the other way counts one day twice, in a monthly figure nobody re-runs.
Only two lists let you choose the order
Most Lending Core lists have a fixed documented order — customers newest-modified first, payments and fundings newest first. Only the native loan and journal-entry lists accept orderBy and sortOrder (ASC/DESC); there is no generic sort parameter anywhere else.
Repeats are OR; different fields are AND
Repeat a documented parameter rather than inventing comma syntax. A comma-separated value arrives as one string, and the endpoint compares it against an enum that has no commas in it:
status=POSTED&status=SETTLED_PENDING_POST
Repeating a value widens the result; adding a different field narrows it.
Search discovers, filtering selects
GET /v1/portfolio/search?q=... is the permission-aware discovery endpoint for customers and loans: name token-prefix, exact current email, phone in standard format, and exact loan account number. Filtering is exact selection inside one collection. Neither supports raw restricted identifiers, account credentials, note text beyond caller sensitivity, or arbitrary database predicates — exact-identifier lookup has its own audited route, POST /v1/customers/lookup.
Servicing closes its filters too, and adds sorting
Implemented servicing collections also use closed filters, but many expose allowlisted sort and order=asc|desc: GET /v1/servicing/tasks accepts exact queue, repeated status/priority, case type, assignee, overdue/sensitive flags, case ID, due-time bounds, limit, offset, sort, and order. Case effects use their declared cursor form instead.