Skip to main content

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 md5 option 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.
Production host

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.

ParameterDescription
companyIdReturns 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.
userIdResolves 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.
md5Set 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:

HeaderValue
secret{{token}} — a PPE API Secret minted for your company
AuthorizationBearer {{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.

note

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​

FieldTypeDescription
idstringUnique identifier for the lender.
namestringDisplay name of the lender.
urlstringLender website, when configured. Empty for many lenders.
rateSheetsarrayRate sheets this lender has enabled for your company — see below.

Rate Sheet fields​

FieldTypeDescription
idstringUnique identifier for the rate sheet.
namestringDisplay name of the rate sheet.
statesarray<string>States the rate sheet is restricted to. Empty means no state restriction.
md5stringMD5 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.

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.

InputWhere it goes
secretsecret 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.
companyIdQuery 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"
Generating the secret yourself

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.

SymptomCauseFix
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 /encodeAES128The 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 variantThe 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 parameterThe secret is Base64 and may contain +, /, or =.URL-encode it, or send it in the secret header instead.
API Key rejected by /encodeAES128The 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.
tip

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.