Developers
Get access

Limits and retries

Requests stop at 30 seconds, concurrency should stay low, and every POST should carry an Idempotency-Key. Together they mean a retry is never charged twice.

30-second request cap

The API stops any request that runs longer than 30 seconds and returns 504 timeout. Set your HTTP client's timeout a little above that, for example 35 seconds, so you receive our response rather than your own timeout.

Keep concurrency low

Send a few requests at a time, not a burst. For bulk work, queue the requests and let a small number of workers take them in turn.

If you send too many, the API returns 429 rate-limited with a Retry-After header. Wait that many seconds before you try again.

HTTP/1.1 429 Too Many Requests
Retry-After: 5

Daily limit

Each account can make 5,000 paid calls and 1,000 test calls a day. The counts start again at midnight UTC. Past a limit, calls return 429 rate-limited with "code": "daily_limit" in the body. Do not retry those: stop until midnight UTC. If you need more paid calls, write to us and we will raise the limit.

Always send an Idempotency-Key

Send a new Idempotency-Key, such as a UUID, with every POST /partners/v1/valuations. Keep it with the request, and reuse it only to retry that same request.

  • Retry with the same key and you are charged once, however many times you retry.
  • Retry while the first call is still running and you get 409 request-in-progress. Wait, then retry with the same key.
  • Send the key with a different request and you get 422 idempotency-key-reused. Use a new key for a new request.

What to retry

StatusTypeRetryHow
401TokenOnceGet a new token first
409request-in-progressYesAfter a short wait, with the same key
429rate-limitedYes, unless its code is daily_limitAfter Retry-After seconds
503data-unavailableYesShortly, with the same key. Never charged.
504timeoutYesWith the same key
400 403 404 422See ErrorsNoFix the request or the account first

A retry loop

const RETRY = new Set([409, 429, 503, 504]);

async function valueWithRetries(body, token) {
  const key = crypto.randomUUID(); // one key for every attempt at this valuation
  for (let attempt = 0; attempt < 4; attempt++) {
    const res = await fetch("https://api.checkmystreet.co.uk/partners/v1/valuations", {
      method: "POST",
      headers: {
        "Authorization": `Bearer ${token}`,
        "Idempotency-Key": key,
        "Content-Type": "application/json",
      },
      body: JSON.stringify(body),
      signal: AbortSignal.timeout(35000),
    });
    if (!RETRY.has(res.status)) return res;
    // A daily limit lasts until midnight UTC: hand it back rather than wait.
    if (res.status === 429 && (await res.clone().json()).code === "daily_limit") return res;
    const wait = Number(res.headers.get("Retry-After")) || 2 ** attempt;
    await new Promise((resolve) => setTimeout(resolve, wait * 1000));
  }
  throw new Error("Valuation failed after 4 attempts");
}

Updated