How an error looks
On the REST API the body is a problem document (RFC 9457). The type is the address of a page below, so a program can look it up.
{
"type": "https://lender.report/errors/invalid-parameter/",
"title": "A value was not accepted",
"status": 400,
"detail": "lane must be one of multifamily, investor_1to4, cre_investor, ...",
"code": "invalid_parameter",
"field": "lane",
"accepted": ["multifamily", "investor_1to4", "cre_investor"],
"did_you_mean": ["multifamily"]
} On the MCP server an input mistake or a limit is a tool error (isError: true, HTTP 200), which is how the protocol lets a model correct its own call. The first text block is one plain sentence naming the field and what is accepted. The second is the same facts as compact JSON: {"error":{"type":"...","status":400,"code":"invalid_parameter","accepted":[...]}}.
The types
| Type | Status | Title | What to do |
|---|---|---|---|
invalid-parameter | 400 | A value was not accepted | A field was given a value the tool does not take. The answer lists the accepted values and, where one is close, the closest one. Correct the value and send the call again. |
unknown-field | 400 | A field is not accepted | The call named a field the tool does not have. The answer lists the fields it does have. Remove the field or correct its spelling. |
sensitive-field | 400 | A sensitive field was refused | The call carried something this site never takes: a Social Security number, tax ID, credit score, income or revenue figure, account number, or a protected trait. The value is never repeated. Send only the facts of the deal. |
not-found | 404 | Not found | The address, lender or place named does not exist here. Search by name first, then use the identifier or the slug that comes back. |
not-in-coverage | 404 | Not in this record | The record does not hold what was asked for. That does not mean it does not exist: the answer names the regulator search to use. |
ambiguous | 409 | More than one fits | A name fits more than one lender or place. The answer lists the candidates with identifiers. Repeat the call with an identifier, or add a state. |
daily-limit | 429 | The daily allowance is used | The calls or rows allowed for the day are used. The answer says when the day starts again (midnight UTC) in seconds and as a time. Retry-After carries the seconds. |
rate-limited | 429 | Too many requests in a few seconds | Requests arrived faster than fair use allows. Wait the seconds given in Retry-After and try again. |
key-not-recognized | 401 | That key was not recognised | The key sent is not on record: it may be mistyped or may have been revoked. Check it, or leave it out to use the no-key limits. |
needs-account | 403 | This needs a free account | The part of the record asked for is not part of no-key access. Sign in, make a key on the account page and send it as a bearer token. |
unavailable | 503 | Temporarily unavailable | The data is not available on this deployment right now. Try again in a minute. |
Limits and headers
A call that is over the day's allowance returns 429 with Retry-After, in seconds, and resets_at. Every response, successful or not, carries RateLimit-Policy and RateLimit ("calls";r=remaining;t=seconds to the reset), X-LR-Rows-Remaining and X-LR-Data-Version. The two RateLimit headers follow an IETF draft that is not yet a standard, and may change. The same numbers are in the limits block of an MCP answer, because an MCP host cannot see headers. The daily numbers are the limits that are enforced; the short-burst courtesy is kept in each server's memory, so do not rely on a number of calls a second.
A key that is not on record is a 401 on the REST API and a tool error on the MCP server. Leave the key out to use the no-key limits.
Questions or a bug: report it or desk@lender.report. Back to the developer docs.