Klantly Developers

Rate limits

How many requests you may make, how to see where you stand and how to back off gracefully.

Limits

LimitAmountDescriptionWindow (seconds)
key_minute120requests per minute for this key60
company_minute300requests per minute for this company60
company_writes60write actions per minute for this company60
company_heavy10heavy actions per minute for this company60
company_day50.000requests per day for this company86400
auth_failures20failed sign-ins per minute from this IP address60

The per-company limit applies to all keys of your company together. Write actions (POST, PATCH, DELETE) also count towards the write limit. The windows are fixed: a per-minute limit starts again at every whole minute, the daily limit at midnight UTC. A refused request counts as well. Need more on a structural basis? Contact support.

Heavy actions have their own, tighter limit: mailing a quote or invoice, fetching a PDF, sending a message in the inbox, sending a review request, sending a customer a message about an appointment, and sending a test message to a webhook endpoint.

There are also a few limits that have nothing to do with the pace of your requests, but that you still see returned as 429 rate_limited:

  • at most 200 uploads (attachments and work-order photos) per company per day, as 429 rate_limited;
  • at most 20 messages per hour in the same conversation, as 429 rate_limited;
  • at most 250 outgoing messages and mails to customers per company per hour (inbox, quote and invoice email together) and no more than 20 sends of the same document per 24 hours. In the inbox this comes back as 429 rate_limited; when mailing a quote or invoice as 403 forbidden.

Headers

Every response tells you where you stand:

Header Meaning
RateLimit-Policy All limits that apply to this request
RateLimit Remaining requests and seconds until the reset, for the tightest limit
X-RateLimit-Limit Size of the tightest limit
X-RateLimit-Remaining Still available in the current window
X-RateLimit-Reset Unix time at which the window starts again

On a 429

A 429 rate_limited has a Retry-After header with the number of seconds you have to wait. The limit field in the response names the limit you hit.

JavaScript
async function request(url, options, attempt = 0) {
  const response = await fetch(url, options);

  if (response.status === 429 && attempt < 5) {
    const seconds = Number(response.headers.get('Retry-After') ?? 1);
    await new Promise((resolve) => setTimeout(resolve, seconds * 1000));

    return request(url, options, attempt + 1);
  }

  return response;
}

Tip

Spread large synchronisations over time and use limit=100, so you fetch more with fewer requests.

Last updated on September 21, 2026