Get Lenders
Use this endpoint to list every lender your company can price with, along with each lender's rate sheets. It is a lightweight discovery call: no pricing search is run, and the response is the same regardless of which authentication method you use.
This is useful for:
- Discovering which lenders and rate sheets your company has access to before building a pricing request
- Populating a lender picker or lender filter in your UI
- Detecting rate sheet changes between calls (see the
md5option below)
How lenders are structured​
A company has an active relationship with many lenders. Each lender publishes one or more rate sheets. A lender appears in the response only when at least one of its rate sheets is enabled for display to your company.
Prerequisites​
You will need:
- Your Company ID, available in Settings → Company Settings.
- Either a PPE API Secret (recommended for server-to-server integrations) or a JWT access token. Both are described in Authentication; the specifics for this endpoint are in Authentication methods below.
This endpoint is served by the Lender Price pricing API host, https://ppe-rapi.lenderprice.com. The examples below use {{domain}} as a placeholder for that host. Your Lender Price contact will provide the equivalent host for any non-production environment you have been given access to.
Request​
GET {{domain}}/rest/v1/rate-sheet-retriever/lenders
Query parameters​
All parameters are optional, but you should always pass companyId.
| Parameter | Description |
|---|---|
companyId | Returns the lenders that have an active relationship with this company. Accepted as a query parameter or as a companyId header. When authenticating with a PPE API Secret, this value also tells the server which company's API key to use when validating the secret (see PPE API Secret), so it is effectively required. |
userId | Resolves the user's company, then returns that company's lenders. Do not use this with a PPE API Secret: the request fails with an HTTP 500 whether or not companyId is also passed. Only pass it when authenticating with a JWT Bearer token. |
md5 | Set to true to include each rate sheet's source-file MD5 hash. Defaults to false. |
If neither userId nor companyId is supplied, the request fails when using a PPE API Secret, and with a Bearer token it falls back to the default marketplace company's lenders, which is almost never what you want.
Headers​
Send one of the following, depending on your authentication method:
| Header | Value |
|---|---|
secret | {{token}} — a PPE API Secret minted for your company |
Authorization | Bearer {{access_token}} — a JWT access token from POST /oauth/token |
Example​
curl --location 'https://{{domain}}/rest/v1/rate-sheet-retriever/lenders?companyId={{companyID}}' \
--header 'secret: {{token}}'
Response​
200 OK
Returns a JSON array of lenders. Each lender contains its rate sheets.
The example below shows a single lender with two rate sheets for brevity. A company typically has access to dozens of lenders and several hundred rate sheets.
[
{
"id": "65a1b2c3d4e5f60001a1b2c3",
"name": "Lender ABC Mortgage",
"url": "",
"rateSheets": [
{
"id": "65a1b2c3d4e5f60001a1b2d1",
"name": "Conventional FNMA",
"states": [],
"md5": ""
},
{
"id": "65a1b2c3d4e5f60001a1b2d2",
"name": "Fannie Mae Parent",
"states": [],
"md5": ""
}
]
}
]
Lender fields​
| Field | Type | Description |
|---|---|---|
id | string | Unique identifier for the lender. |
name | string | Display name of the lender. |
url | string | Lender website, when configured. Empty for many lenders. |
rateSheets | array | Rate sheets this lender has enabled for your company — see below. |
Rate Sheet fields​
| Field | Type | Description |
|---|---|---|
id | string | Unique identifier for the rate sheet. |
name | string | Display name of the rate sheet. |
states | array<string> | States the rate sheet is restricted to. Empty means no state restriction. |
md5 | string | MD5 hash of the rate sheet's source file. Populated only when md5=true is passed and the rate sheet was loaded from a source file; otherwise empty. Compare this value between calls to detect when a rate sheet has been updated. |
Fetching specific lenders​
A POST variant returns the same shape for only the lenders you name. Send a JSON array of lender IDs as the body:
curl --location --request POST 'https://{{domain}}/rest/v1/rate-sheet-retriever/lenders?companyId={{companyID}}' \
--header 'secret: {{token}}' \
--header 'Content-Type: application/json' \
--data '["65a1b2c3d4e5f60001a1b2c3", "65a1b2c3d4e5f60001a1b2c4"]'
Authentication methods​
The server checks every request to this endpoint the same way: if a secret is present it is validated as a PPE API Secret; otherwise a Bearer token is required. A request with neither is rejected.
PPE API Secret (recommended)​
This method needs only your company's API Key and the User ID of any user in your company. No password or OAuth client is involved, which makes it the simplest option for server-to-server integrations.
| Input | Where it goes |
|---|---|
secret | secret header (or a URL-encoded secret query parameter). An encrypted, time-limited value derived from your User ID and keyed with your company's API Key. |
companyId | Query parameter. The server uses it to look up your company's API Key and validate the secret, so a secret only works for the company it was minted for. |
Step 1 — Mint a secret. Call the unauthenticated helper endpoint described in Authentication → PPE API Secret. The optional duration is in hours (default 24; values above 48 are silently capped at 48). The response's valid field is the ISO-8601 expiry time. The server continues to accept the secret for one hour after that timestamp.
curl --location 'https://{{domain}}/encodeAES128/{{apiKey}}/{{userId}}?duration=24'
{
"valid": "2026-10-03T18:23:41.954Z",
"secret": "Q2xpZW50U2VjcmV0RXhhbXBsZU9ubHlOb3RSZWFsVmFsdWUxMjM0NTY3ODkwPT0="
}
Step 2 — Call the endpoint with the secret in the header.
curl --location 'https://{{domain}}/rest/v1/rate-sheet-retriever/lenders?companyId={{companyID}}' \
--header 'secret: {{token}}'
Or mint and use the secret in one step (requires jq):
DOMAIN='ppe-rapi.lenderprice.com'
COMPANY_ID='{{companyID}}'
API_KEY='{{apiKey}}'
USER_ID='{{userId}}'
SECRET=$(curl -s "https://$DOMAIN/encodeAES128/$API_KEY/$USER_ID?duration=24" | jq -r .secret)
curl -s "https://$DOMAIN/rest/v1/rate-sheet-retriever/lenders?companyId=$COMPANY_ID" \
-H "secret: $SECRET"
The helper endpoint is a convenience, not a requirement. You can produce the same value locally: AES-encrypt the string <userId>|<expiryMillis>|v2 in ECB mode with PKCS5 padding, using the raw bytes of your API Key as the key, and Base64-encode the result. Because the API Key is used directly as the AES key, it must be exactly 16, 24, or 32 characters long.
JWT Bearer token​
You can also send the standard access token returned by POST /oauth/token (see Authentication → Authen JWT). The server reads the user from the token and loads that user's company, so the token must have been issued by the same environment you are calling. A token from a different environment is rejected.
curl --location 'https://{{domain}}/rest/v1/rate-sheet-retriever/lenders?companyId={{companyID}}' \
--header 'Authorization: Bearer {{access_token}}'
Errors and troubleshooting​
Authentication failures on this endpoint currently surface as HTTP 500 responses rather than 401/403, so check the error message in the body.
| Symptom | Cause | Fix |
|---|---|---|
500 with AccessDeniedException: Access Denied. | No secret header and no Authorization header. | Send one of the two headers. |
500 with NullPointerException (using a secret) | The secret is malformed, expired, or was not minted with this company's API Key. Also returned when userId is passed alongside a secret. Decryption failures surface as a bare NPE, not an authentication error. | Mint a fresh secret with your company's API Key, pass companyId only, and drop userId. |
500 with UndeclaredThrowableException (using a secret) | companyId is missing, or does not match the company whose API Key minted the secret. | Pass the correct companyId as a query parameter or header. |
500 with NullPointerException (using a Bearer token) | The token's user does not exist in the environment you are calling (for example, a token from a non-production environment sent to production). | Obtain a token from the same environment's /oauth/token. |
400 Please provide a key and/or a user-id in the header. or 500 StringIndexOutOfBoundsException from /encodeAES128 | The API Key and User ID were sent as headers instead of path segments. The header form is not supported. | Use the path form: /encodeAES128/{apiKey}/{userId}. |
400 with an empty body from the POST variant | The request body is not a plain JSON array of lender ID strings (for example, an object wrapper or an array of objects). | Send ["<lenderId>", "<lenderId>"] with Content-Type: application/json. |
| Secret rejected when sent as a query parameter | The secret is Base64 and may contain +, /, or =. | URL-encode it, or send it in the secret header instead. |
API Key rejected by /encodeAES128 | The key is used directly as the AES key. | The API Key must be exactly 16, 24, or 32 characters. Contact Lender Price if yours is not. |
Empty array [] | The company has no lenders with a rate sheet enabled for display, or the POST body listed IDs that are not lenders of this company. | Verify the Company ID and lender IDs, and that rate sheets are enabled in Settings. |
The lender name returned here is the same value that appears on each pricing result as lineResult.ratePeriod.company.name, so you can use this list to group or label pricing results by lender. See Pricing Response for details.