Matchai Docs

Rate limits

The request limits on Matchai's public MCP server and listing search today, how to read them, and how limits and RateLimit headers will work in the Matchai API.

Limits keep Matchai fast for everyone. This page states what the public surfaces allow today, and how the planned Matchai API will report and apply its limits.

On the public surfaces

These limits apply to the surfaces you can use today without a key. Each is counted per calling address: the address your requests come from. Callers behind a shared address, such as an office network or a hosted assistant, share one allowance.

SurfaceLimitWhen you go over
MCP server tool calls (tools/call at https://matchai.co/mcp)600 per minuteThe call returns a tool result with isError: true and a message asking you to try again in a minute. The HTTP status is still 200.
Listing search (https://matchai.co/ask, GET and POST together)60 per minute429 with the error rate_limited and a Retry-After of 60 seconds.

A few details:

  • The MCP limit counts tools/call only. The handshake, tools/list and the other methods are not counted. It is an abuse guard, set high enough that a busy assistant host does not reach it.
  • Listing search can also answer 503. When search is temporarily unavailable, it answers 503 with the error unavailable and a Retry-After of 30 seconds. Wait that long, then try again.
  • AI-readable pages have no per-minute figure, but ask you to be polite: about one request per second per host. To read a whole site, fetch its llms-full.txt instead of crawling page by page. On a 429, wait for Retry-After. The discovery files change at most about once a minute, so polling faster returns the same content.

See listing search and the MCP server for the full picture.

Handle a limit in code

ask-with-wait.mjs
async function ask(query) {
  const response = await fetch(`https://matchai.co/ask?query=${encodeURIComponent(query)}`);

  if (response.status === 429 || response.status === 503) {
    const wait = Number(response.headers.get('Retry-After') ?? 60);
    await new Promise((resolve) => setTimeout(resolve, wait * 1000));
    return ask(query); // Try once more after the wait.
  }

  return response.json();
}

Add a counter in real code, so a request that keeps failing eventually gives up.

In the Matchai API

Coming soon

The Matchai API limits requests per connection: one Matchai account connected to one app. The figures are not published here yet. Do not hard-code them: the API tells you where you stand on every response.

Rate limit headers

Every response carries three headers:

HeaderMeaning
RateLimit-LimitRequests allowed in the current window for this connection
RateLimit-RemainingRequests left in the current window
RateLimit-ResetSeconds until the window resets
Response headers
RateLimit-Limit: 120
RateLimit-Remaining: 117
RateLimit-Reset: 41
Matchai-Request-Id: req_7Hq2LmZ9xV4c

The numbers above are an illustration. They are not the real limit.

When you go over

A request over the limit is refused with 429 and does nothing. The response carries Retry-After, the number of seconds to wait:

Response (429)
{
  "error": {
    "type": "rate_limit_error",
    "code": "rate_limited",
    "message": "Too many requests. Try again in 20 seconds.",
    "doc_url": "https://matchai.co/docs/developers/errors#rate_limited",
    "request_id": "req_7Hq2LmZ9xV4c"
  }
}

A 429 is safe to retry. Wait for Retry-After, then send the request again with the same Idempotency-Key, so that nothing happens twice. Retry safely has a complete example.

Who shares a limit

  • All the keys of one account share one limit, because they belong to one connection. A second key does not buy more room. See API keys.
  • Two professionals connected to the same app have separate limits. One broker's busy morning does not slow another broker's connection.
  • Public operations work without credentials, with lower limits. Looking up a professional's published profile or listings needs no key. Those requests are counted per IP address, and sending a key or token raises the limit. They are marked Free in the API reference.

Limits are not Energy limits

An action that uses Matchai Energy can be refused for two other reasons, and neither is a 429:

  • The account has run out of Energy: 402 with the code insufficient_energy.
  • The account holder set an Energy limit for your connection, and you reached it: 402 with the code energy_limit_reached.

Waiting does not clear either one. See errors.

Stay well under the limit

  • Read the headers. Slow down when RateLimit-Remaining is low, and pause until RateLimit-Reset when it reaches zero.
  • Listen instead of polling. Webhooks tell you when a lead arrives or a listing changes, with no requests at all.
  • Sync what changed. Use updated_since on list endpoints, and ask for limit=100 pages, the largest page.
  • Spread out bulk work. Importing a hundred contacts is a queue, not a burst.
  • Repeat only what failed. Idempotency keys let you retry a single request safely.
paced-fetch.mjs
export async function pacedFetch(url, init) {
  const response = await fetch(url, init);

  const remaining = Number(response.headers.get('RateLimit-Remaining'));
  const reset = Number(response.headers.get('RateLimit-Reset'));

  // Nearly out of requests: wait for the window to reset before the next call.
  if (remaining <= 1 && reset > 0) {
    await new Promise((resolve) => setTimeout(resolve, reset * 1000));
  }

  return response;
}

On this page