Errors and limits

The /v1 error format and every error code, paging, idempotency keys, rate limits and the daily property search allowance.

This page covers what every /v1 request shares: the error format, paging, safe retries of creates, and the limits. Listings and property-source routes keep the error shape they have always had; Authentication shows both.

Read an error

Every error on /v1 has the same envelope:

json
{  "error": {    "code": "API_KEY_SCOPE_MISSING",    "message": "This API key is missing the crm:write scope.",    "status": 403,    "details": { "missing": ["crm:write"] }  },  "requestId": "0b6f8f0e-6d2b-4b8a-9f43-5f1c2a7d9e11"}

Branch on code. message is for people and can change. details is present when there is more to say, for example the missing scopes or a list of validation issues.

A request that fails validation answers 400 with VALIDATION_FAILED and the problems in details.issues. Unknown query parameters and body fields are ignored on most routes, so check spelling against the route's page. A body sent to a route that takes none is refused. A JSON body sent without Content-Type: application/json is not read and answers 400:

json
{  "error": {    "code": "VALIDATION_FAILED",    "message": "The request is not valid. See details.issues.",    "status": 400,    "details": {      "issues": [{ "path": "query.limit", "message": "Too big: expected number to be <=100" }]    }  },  "requestId": "5b2d7c1e-3f4a-4e89-b6a0-9c8d7e6f5a43"}

Error codes

StatusCodeWhen
400VALIDATION_FAILEDA parameter or body is missing or malformed. See details.issues
400BAD_REQUESTThe request is not valid in another way
401UNAUTHENTICATEDThe key is missing, malformed, unknown, revoked or expired, or you sent a session token. The response carries a WWW-Authenticate: Bearer realm="Fondaro API" header
403API_KEY_SCOPE_MISSINGThe key lacks a scope. details.missing lists them
403ORG_ADMIN_REQUIREDOnly an organization admin can do this
403SUBSCRIPTION_REQUIREDThis needs an active Fondaro subscription
403ORG_DISABLEDThe organization is disabled
403API_KEY_HAS_NO_OWNERThe key has no owner. Create a new key. Rotating an older key does not change this
403API_KEY_LEGACYThe key was made before 4 October 2026. /v1 does not accept it. Create a new key; rotating the older key does not change this
403API_KEY_HAS_WEBSITESThe key lists allowed websites. /v1 is for servers, so make a key without websites for it
409API_KEY_LIMIT_REACHEDCreating a key would pass the limit of 10 active keys per person or 50 per organization. Revoke one you no longer use
403API_KEY_OWNER_NOT_IN_ORGANIZATIONThe key's owner left the agency
403API_KEY_ORIGIN_NOT_ALLOWEDA browser request. /v1 is for servers
403API_OPERATION_NOT_DECLAREDA route that does not declare its access is refused. If you see this, tell support
403FORBIDDENYou do not have access to this
404NOT_FOUNDThe record does not exist or is not yours. For a record the message is "<Resource> not found.", whichever it is. An unknown path, or a method a path does not support, answers "No such endpoint."
409CONFLICTThe request conflicts with the current state
409IDEMPOTENCY_KEY_REUSED, IDEMPOTENCY_KEY_IN_PROGRESSSee Retry a create safely
413PAYLOAD_TOO_LARGEThe body is too large
415UNSUPPORTED_MEDIA_TYPEThe body's content type is not supported. Send Content-Type: application/json
422UNPROCESSABLEThe request is understood but cannot be applied
429RATE_LIMITEDToo many requests. Wait Retry-After seconds
429DAILY_LIMIT_REACHEDThe daily property site search allowance is used up
502, 503INTERNALA service Fondaro depends on is briefly unavailable. Retry with backoff
500INTERNALSomething went wrong on our side
503AUTH_UNAVAILABLEFondaro could not check the key's owner just now. Retry shortly

A 404 does not tell you whether a record exists: a lead you cannot see answers the same as one that does not exist. A domain error can carry its own code and extra details; the page for that route lists it.

A 5xx never contains a stack trace or a message from a service behind Fondaro.

Request ids

Every /v1 response, success or error, has an X-Request-Id header, and every error carries the same value as requestId. Fondaro generates it; a value you send is ignored. When you contact support, send the requestId, the time, the method and the path. Never send the key.

Page through a list

A list is an object with data and hasMore:

json
{  "data": [{ "id": "c7d2…" }, { "id": "b61a…" }],  "hasMore": true,  "nextOffset": 2}

Each route's page names its paging style and its limit range. The styles that exist:

StyleHowUsed by
Page numberSend page and limit. Leads answer page, limit and an exact total; brochures answer hasMore and, when it is known, totalLeads, brochures
OffsetSend offset and limit. While hasMore is true, send nextOffset as the next offset. Calls, viewings and documents also carry totalLead timeline, calls, viewings, documents
Older thanSend before with the time of the last message you haveA lead's conversation
CappedOne page, at most a fixed number of rows. hasMore: true means more exist: narrow your filters to reach themDeals, tasks, emails, members, buyer requests, collections, open houses
Whole listEverything, in one response, with hasMore: falseNotes, tags, teams

limit is an upper bound, so a page can hold fewer rows than asked for. Offset paging has no snapshot: rows added or removed while you page can shift between pages.

Retry a create safely

Send an Idempotency-Key header on a POST that creates something (for example a lead, a task, a note or a deal; the route's page says when it accepts one). The header is optional: 1 to 255 visible ASCII characters, such as a UUID.

bash
curl -X POST https://api.fondaro.com/v1/leads \  -H "Authorization: Bearer $FONDARO_API_KEY" \  -H "Idempotency-Key: 6f1c2d3e-0a4b-4c5d-8e9f-1a2b3c4d5e6f" \  -H "Content-Type: application/json" \  -d '{ "firstName": "Anna", "lastName": "Berg", "email": "anna@example.com", "phoneNumber": "+46701234567", "crmStatus": "lead" }'
  • Retry after a timeout or a 5xx: send the same key with the same request. If the first attempt succeeded, you get its response back with Idempotent-Replayed: true, and nothing is created twice.
  • Same key, different request: 409 with IDEMPOTENCY_KEY_REUSED. A request is the same when the method, the path and the JSON body match exactly, including key order. The query string is not compared.
  • Same key while the first request still runs: 409 with IDEMPOTENCY_KEY_IN_PROGRESS. Wait a moment and retry. The marker lasts up to 5 minutes.
  • Failed requests are not stored. A 4xx or 5xx frees the key, so you can fix the request and send it again with the same key.
  • Responses are kept for 24 hours. Keys belong to the API key that sent them.
  • Responses that carry a secret, or are larger than 512 KB, are not stored. A retry runs the request again.

Without the header, a retried create creates again. If the idempotency store is briefly unavailable, requests still run, without protection.

Stay within rate limits

Each API key has its own allowance per endpoint:

WindowRequests
A minute120
10 minutes600
An hour3,000

Fondaro can raise one key's per-minute limit for a busy integration; the 10-minute and hourly windows scale with it. Responses carry the remaining allowance in X-RateLimit-Limit-<window> and X-RateLimit-Remaining-<window> headers, one pair per window (short, medium, long).

Over a limit, the API answers 429 with RATE_LIMITED, a Retry-After header in seconds and an X-RateLimit-Reset header with the reset time in epoch seconds. Wait that long, then retry; slow down rather than retry at once.

Two reads cost more to run and share one limit: semantic search of your CRM (POST /v1/search) and listing matches (POST /v1/listing-matches). Together they allow 30 requests a minute per key, and 30 a minute for your whole organization across all its keys, so creating more keys does not raise it. Over it, the API answers 429 with RATE_LIMITED and Retry-After. This budget is separate from the one the n8n integration API uses.

Plan around the daily search allowance

Searches of the property sites you can use with Fondaro share one allowance per organization: 300 upstream requests a day, counted from midnight UTC. It is shared by the dashboard, Ask Fondaro and every API key, so a busy script uses what your team would otherwise have. Cached results are free. When it is used up:

  • On /v1, the API answers 429 with DAILY_LIMIT_REACHED.
  • On POST /property-sources/{source}/search and the other /property-sources routes, which keep their own error shape, it answers 400 with PROPERTY_PORTAL_QUOTA_EXHAUSTED.

Either way, wait for the next UTC day.

Handle new versions

The /v1 routes change only by adding: new routes, new response fields, new optional parameters and new error codes. Ignore fields and codes you do not know. A breaking change would be a new version path, /v2, announced in the changelog, with /v1 kept running.