Errors

Every failure on this API has the same shape — including a wrong path, a wrong method and an unparseable body. There is one envelope to handle, not one per endpoint.

The envelope

{
  "error": "invalid_parameter",
  "message": "radius_km must be 500 or less.",
  "docs_url": "https://docs.investviews.ai/errors.html",
  "parameter": "radius_km",
  "request_id": "req_01JQ8Z..."
}
Field Always present What it is
error yes the machine-readable code. Branch on this
message yes a human sentence. Never branch on this
docs_url yes where to read more
parameter no which parameter was at fault, on the 400s that name one
request_id no our handle on this failure. Quote it to support

Other fields appear where they help — limit, resets_at, upgrade_url, did_you_mean. They are additive: treat unknown keys as forward compatibility, not as an error in your client.

Branch on error, never on message

message is written for a person and can be reworded at any time. A client that matches on its text breaks on a copy edit, and breaks silently — it stops recognising a condition it used to handle.

Every code

Credentials and billing

Code Status Meaning
invalid_token 401 no usable credential: header absent, malformed, unknown, or revoked
subscription_inactive 402 the subscription that owns this token is not active
quota_exhausted 402 this cycle's request allowance for the group is spent
read_only_token 403 a read-only token was used on a write endpoint

Three different problems with three different fixes. See Authentication for why a lapsed plan is 402 rather than 401, and Quota for what to do when the allowance runs out.

The request

Code Status Meaning
missing_parameter 400 a required parameter was not sent
invalid_parameter 400 a parameter was sent but its value is unusable
invalid_cursor 400 the pagination cursor is not one we issued for this query
malformed_request 4xx the request could not be processed as sent (method, body, headers)
too_many_hexes 422 the territory exceeds the per-request cell budget

invalid_cursor usually means a cursor was constructed by hand or reused across a different query. Follow the cursor the response gives you.

too_many_hexes means the territory is too large to answer in one request. Ask for a coarser resolution, or split the territory.

Geography

Code Status Meaning
unknown_place 404 no place, cell or key matched — inside a market we do serve
not_covered 404 this API holds no geographic data for that country
resolution_not_in_plan 403 the requested H3 resolution is finer than the plan allows

unknown_place and not_covered are both 404 and they mean different things. The first says "we serve this country, but that name is not in it" — check the spelling, or browse with /geo. The second says "we do not serve that country at all" — check /coverage before concluding a market does not exist, because a market can hold listings without being searchable by name.

Limits and faults

Code Status Meaning
rate_limited 429 too many requests this minute
not_found 404 no such resource or path
internal_error 500 a fault on our side
reports_unavailable_for_country 422 the report pipeline does not serve that country

What to retry

Only two of these are worth retrying. The rest describe something about the request that will be just as wrong the second time.

Code Retry? How
rate_limited yes wait Retry-After seconds, then retry
internal_error yes back off and retry. Quote request_id if it persists
quota_exhausted not until the cycle rolls X-Quota-Reset says when
everything else no fix the request, the token, or the billing

Honour Retry-After rather than guessing

A 429 carries Retry-After in seconds. Backing off by a number you invented is how a client that hit the limit once keeps hitting it.

Rate limits

Separate from quota. Quota is your allowance for the billing cycle; the rate limit is how fast you may spend it.

Header Meaning
X-RateLimit-Limit requests per minute for this group. On every response
X-RateLimit-Remaining requests left in this minute
Retry-After seconds until the window rolls. On 429 only

The limit applies to uncounted groups too. Free does not mean unmetered in time — see Quota.

Handling failures well