application/problem+json bodies with a code you can switch on and a detail you can show. The type URL is a link to this page, anchored at the code:
code, never on detail or title: the codes are stable and their wording is not. errors[] names each offending parameter on a 400 (param, message, code). A 429, a 503 pool_saturated or ledger_unavailable, and a 403 plan_limit on the name-search day cap carry Retry-After.
The 500 never echoes a database message: quote request_id. Every response the API answers also carries it as the X-Request-Id header. A refusal the gateway answers itself carries it as zp-rid: see Request ids.
Two producers share this catalogue. The gateway at api.investorlift.com answers its own refusals in this shape before a request reaches the API. Those refusals include a missing key, a spent plan budget and a plan’s per-minute limit. Each such code says so in its section. https://developers.investorlift.com/problems.json is the codes a key at api.investorlift.com can meet as JSON, generated from the same source as this page.
What to do
Every code
One row per code a key at api.investorlift.com can meet, generated from the service. The codes only the internal host answers are under Partners and staff. Codes are stable. Titles and wording can change. Each links to its own section below.400 Bad request
dataset_unavailable
400 Dataset unavailable. A name in datasets is not a block this API serves. Either the name is unknown, or no delivery carries the dataset (contact, demographic, foreclosure, batchrank). The body’s errors[] names each one.
geometry_conflict
400 Geometry conflict. The geometry parameters contradict each other. Conflicts: radius_miles with bbox, property_id with a point or a bbox, a lone lat or lng, or zip beside city. A place (zip or city) beside radius_miles, bbox or property_id is also a conflict. A place on a route that ranks around a point (buyers/match) is also a conflict. A point beside a place is the reference point, not a conflict. On the coverage route, two place groups at once are a conflict, and so is a lone lat or lng. The place groups of the coverage route are lat and lng, county, zip and market.
geometry_required
400 Geometry required. The request needs one geometry: lat and lng (with radius_miles), bbox, property_id, zip or city.
invalid_cursor
400 Invalid cursor. The API cannot decode the cursor, or issued it for another query, sort, weight set or dataset version. Restart from page 1.
invalid_id
400 Invalid id. Every id has a prefix. The forms: deal_<32 hex>, prop_<32 hex>, inv_<12 hex>, agt_<12 hex>, wl_<32 hex> (an Investorlift listing), wsr_<12 hex> (a wholesaler), len_<12 hex> (a lender). The prefix is part of the id.
market_required
400 Market required. The investor or agent id exists in more than one loaded market. Or you asked for a lender list (GET /v1/lenders) while the API has several markets loaded, and named no market. A lender list ranks inside one market. Pass market=. The body lists the markets.
quicklist_unavailable
400 Quicklist unavailable. A quicklist name in quicklists, any_quicklists or not_quicklists is not one this API can compute. Either the name is unknown, or no delivery carries its dataset. Examples: notice-of-default, preforeclosure, active-auction, has-hoa and for-sale-by-owner. The body’s errors[] names each one and the dataset that unlocks it.
sort_requires_point
400 Sort requires a reference point. sort=distance needs lat and lng, or property_id. With bbox alone, or with a zip or city without a point, the default sort is date_desc.
unknown_parameter
400 Unknown parameter. The query carries a parameter the endpoint does not define. Bracketed list syntax such as kind[] counts as an unknown parameter. A list is comma-separated values or repeated keys.
validation_error
400 Validation error. A parameter failed validation. errors[] names each offending parameter.
401 Unauthorized
unauthorized
401 Unauthorized. The request carries no bearer key, or the key is malformed or unknown.
Both the gateway at api.investorlift.com and the API itself return it. The gateway’s own check runs first.
403 Forbidden
payment_overdue
403 Payment overdue. The subscription’s last payment failed and the grace period passed. The gateway blocks the key until you update the card under Manage Billing in the console. A refused request charges nothing.
The gateway at api.investorlift.com returns it, not the API itself. A partner who calls an internal host never sees it.
plan_limit
403 Plan limit. The request exceeds what this plan allows. The limits: geometry, the daily name-search cap, an MCP page over the plan’s largest, the change series’ weeks over /mcp, monitors or export rows. The response names the limit. Upgrade in the console.
quota_exceeded
403 Quota exceeded. Your requests spent the plan’s credits for the billing period: the allowance, or on Growth and Scale the overage ceiling. On the Free plan, spent lifetime credits get the same refusal, with stop budget in the body. The body carries used and line. Every route that charges credits answers it until the period resets or the plan changes. A re-read of a record you already hold gets the same refusal, from the origin before it prices the page and from the gateway’s check. The routes priced at 0 and the MCP handshake keep answering.
Both the gateway at api.investorlift.com and the API itself return it. The gateway’s own check runs first.
subscription_required
403 Subscription required. The key has no active plan subscription: the gateway found none, or forwarded no subscription for a route that charges credits.
Both the gateway at api.investorlift.com and the API itself return it. The gateway’s own check runs first.
404 Not found
not_found
404 Not found. No such route, or no such deal, investor, agent, lender or parcel in any loaded market.
406 Not acceptable
not_acceptable
406 Not acceptable. The Accept header names a representation the endpoint does not produce. No Accept header, / and application/* mean JSON. text/csv works only where a route documents it.
410 Gone
gone
410 Gone. A retired investor, agent or lender id. superseded_by is null. Search by name instead (/v1/investors/search, /v1/agents/search or /v1/lenders/search).
422 Unprocessable
addresses_unavailable
422 Addresses unavailable. You called GET /v1/properties/resolve with address, but no market has a published address table: meta.coverage[].address_as_of is null on every market.
agents_unavailable
422 Agents unavailable. You called a /v1/agents route for a market with no published agent registry. Its meta.coverage[].agents_data_end is null, so the API can find or profile no agent. An empty answer reads as “no such agent”, so the API refuses. Wait for the market’s agent registry. The API still serves the listing agents on deal and property rows, without ids.
ambiguous_address
422 Ambiguous address. The address matches several parcels: the units of one building, or twins of the line in the ZIP or city. The body’s candidates[] lists them with their units.
ambiguous_apn
422 Ambiguous APN. The APN matches several parcels that are not the same parcel. candidates[] lists them.
auction_unavailable
422 Auction counts unavailable. You gave buys_at_auction, buys_reo or bought_auction_kind for a market with no published foreclosure-auction and REO purchase counts. Its meta.coverage[].auction_counted is false: its registry predates the counts. So “bought at auction or not” has no answer, and an empty page reads as “nobody buys at auction”. Drop the parameter, or wait for the market’s registry rebuild. The API still serves the investor and deal rows, with investor.auction and bought_auction_kind null.
cash_sale_unavailable
422 Cash sale proxy unavailable. You gave the cash-buyer quicklist or the sale.cash_sale filter for a market where meta.coverage[].parcel.sale_mortgage_measured is false. Its delivery records a purchase mortgage on fewer than one priced last sale in five, so cash_sale_proxy is null on every parcel. So “cash or not” has no answer: an empty page reads as “no cash buyers” and a full one as “every priced sale was cash”. Drop the quicklist or the filter. Where meta.coverage[].auction_counted is true, the measured cash signals are the auction block, bought_auction_kind, buys_at_auction and buys_reo.
csv_cap_exceeded
422 CSV cap exceeded. The CSV export exceeds the 50,000-row cap (X-Row-Cap). The API counts the filtered set before the first row streams. Narrow the geometry or filters, or on the loans of a lender the recorded_from and recorded_to window.
Response headers: X-Row-Cap: 50000.
dated_refused
422 Dated data refused. The request set require_current: true and also names a dated block (valuation, financing or liens) in a filter, the sort or datasets. A dated block is a snapshot valued at the slice date in meta.coverage[].parcel.financing.as_of. Drop require_current to get the dated blocks with their meta.dated[] stamp, or drop the dated filters, sort and datasets.
history_unavailable
422 History unavailable. The parcel lies outside the ZIP codes the history lake covers for its market (meta.coverage[].parcel.history.zips), or the market has no history tables. So no timeline or listing cycle exists for the parcel. An empty timeline reads as “nothing changed”, so the API refuses.
lenders_unavailable
422 Lenders unavailable. You called a /v1/lenders route for a market with no published lender registry, so the API can find, rank or profile no lender. The registry tables are absent, or the market has no financing slice to build them from, so meta.coverage[].lenders is null there. An empty answer reads as “no such lender”, so the API refuses.
GET /v1/lenders/{id}/borrowers and the deed-link and borrower-match filters answer it too, before any query, on a registry that predates both. Those filters are purpose, outcome, deal_kind, investor_id and investor_only, and such a registry has meta.coverage[].lenders.purchase_measured, investor_lending_measured or borrowers_measured false. Every phase-5 parameter and route answers it too on a registry built before the place rankings, or on a host without the h3 extensions. Phase 5 is a period other than 24m, a geometry, foreclosed, cell, GET /v1/lenders/{id}/rankings and /cells, and its fields are null there. Wait for the market’s lender build. The API still serves the financing block on parcels where the slice is.
listings_unavailable
422 Listings unavailable. You gave listing_status, or asked the comps route for source=mls, for a market with no published listing tables. Its meta.coverage[].listings_data_end is null, so “listed or not” has no answer. An empty page reads as “nothing listed”, so the API refuses. Drop the parameter, or ask the comps for source=deed or both, or wait for the market’s listing feed.
outside_coverage
422 Outside coverage. The point (or parcel centroid) lies farther from every loaded market’s coverage bbox than its point tolerance, or the bbox intersects none of them. The tolerance is meta.coverage[].point_tolerance_miles on any list response: 20 miles for a metro, 2 for a county market. The deal, investor, wholesale-listing and short-term-rental lists answer it for a zip or city that no parcel of a loaded market carries. The body then carries zips_unknown or city, and the loaded markets. A lender list (GET /v1/lenders) answers it too when the named zip, city or county lies outside the counties its market’s lender registry covers. Those counties are meta.coverage[].lenders.counties, and the body carries counties_covered. A ZIP of an unloaded county is not a place with no lending.
parcels_unavailable
422 Parcel products unavailable. You called POST /v1/properties/search, a financing, permits, history or listing-history route, or GET /v1/markets/{market}/changes, for a market with no published parcel product tables. Its meta.coverage[].parcel is null, so the API can find no parcel. An empty answer reads as “nothing matches”, so the API refuses. Wait for the market’s parcel build.
str_unavailable
422 Short-term rental data unavailable. You gave the str_status, str_business_use, str_operator or str_holdings_min filter, or called GET /v1/str-parcels, for a market with no published short-term rental tables. Its meta.coverage[].str_as_of is null, so “licensed or not” has no answer. An empty page reads as “no licence”, so the API refuses. Drop the parameter, or wait for the market’s STR build. The API still serves the deal, investor and property rows, with their short_term_rental and str blocks null.
wholesale_unavailable
422 Wholesale transactions unavailable. You called the /v1/wholesale-listings, /v1/wholesalers or /v1/investors/{id}/wholesale-purchases route, or the source=investorlift or bought_on_investorlift filter, for a market with no published Investorlift wholesale tables. Its meta.coverage[].wholesale_as_of is null, so the API can find no listing or wholesaler. An empty answer reads as “nothing listed”, so the API refuses. Wait for the market’s wholesale tables. The API still serves the deal, investor and property rows, with their wholesale blocks null.
429 Too many requests
rate_limited
429 Rate limited. The request exceeded the per-key, per-IP or per-X-On-Behalf-Of budget. Retry-After says when to retry.
Both the gateway at api.investorlift.com and the API itself return it. The gateway’s own check runs first.
Response headers: Retry-After: 12.
500 Internal error
internal_error
500 Internal error. Unexpected failure. The body carries the request_id to quote. The API echoes nothing from the database.
503 Service unavailable
database_unavailable
503 Database unavailable. The service failed to reach or keep a connection to the database.
ledger_unavailable
503 Ledger unavailable. The credit ledger is unreachable. Retry after the interval in Retry-After. The API charged nothing.
Response headers: Retry-After: 5.
pool_saturated
503 Pool saturated. No pooled connection came free within 2 s, or the pod reached its in-flight cap. Retry-After: 1.
Response headers: Retry-After: 1.
504 Gateway timeout
statement_timeout
504 Statement timeout. The query exceeded the 10 s statement timeout. Narrow the geometry or filters.
Partners and staff
The internal host alone answers the codes below. Azpka_ key at api.investorlift.com never meets them. The gateway is the reason. It names the developer in X-On-Behalf-Of itself. It presents a key that asks for no contact field. It routes neither the probes nor the routes of the internal host (the pins route). Each keeps its own section, so an error body’s type URL lands here whichever host sent it.
on_behalf_of_required
400 X-On-Behalf-Of required. A key that carries a contact scope (contact or mcp_contact) must send X-On-Behalf-Of: <opaque Investorlift user or org id> on every request.
Internal host only: a zpka_ key at api.investorlift.com never meets this code. The gateway is the reason. It names the developer in X-On-Behalf-Of itself. It presents a key that asks for no contact field. It routes neither the probes nor the routes of the internal host (the pins route).
scope_required
403 Scope required. The key lacks the scope this endpoint or representation needs (deals or contact).
Internal host only: a zpka_ key at api.investorlift.com never meets this code. The gateway is the reason. It names the developer in X-On-Behalf-Of itself. It presents a key that asks for no contact field. It routes neither the probes nor the routes of the internal host (the pins route).
pin_cap_exceeded
422 Pin cap exceeded. The geometry holds more deals than cap. The body carries n_deals and cap, and suggestion is “cells”.
Internal host only: a zpka_ key at api.investorlift.com never meets this code. The gateway is the reason. It names the developer in X-On-Behalf-Of itself. It presents a key that asks for no contact field. It routes neither the probes nor the routes of the internal host (the pins route).
not_ready
503 Not ready. The readiness check failed: no database, absent table privileges, or empty coverage.
Internal host only: a zpka_ key at api.investorlift.com never meets this code. The gateway is the reason. It names the developer in X-On-Behalf-Of itself. It presents a key that asks for no contact field. It routes neither the probes nor the routes of the internal host (the pins route).