Skip to content

Rate limits and caching

To protect fair use, some endpoints are limited per client IP with a fixed time window.

Endpoint group Limit
Calculation (calculateByKey, calculateTool; counted together) 60 requests / 60 s
Search (searchTools) 60 requests / 60 s
Other read endpoints (list, categories, definition) Cached; no separate counter
Body size At most 16 KB (413 PAYLOAD_TOO_LARGE)
Request duration 15 s (504 TIMEOUT)

Limited endpoints return the following in every response (readable from the browser):

RateLimit-Limit: 60
RateLimit-Remaining: 59

When the limit is exceeded, 429 RATE_LIMITED and the following information come back:

HTTP/1.1 429 Too Many Requests
Retry-After: 23
{ "error": { "code": "RATE_LIMITED", "message": "…", "details": { "retryAfterSeconds": 23 } }, "requestId": "…" }

Wait for Retry-After, then retry. While waiting, show the user a message such as “too many attempts”.

  • Cache definitions. The getToolByKey response is cached for a short time (max-age=5, 30 s on the CDN, 5 min stale-while-revalidate); in your own application you can keep it for minutes to hours. For freshness, send version in the calculation (Calculation).
  • Fetch the category tree once and keep it.
  • Use a delay (debounce) on search: while the user types, request after 250–400 ms of silence rather than on every keystroke. Do not ask the same query again.
  • Trigger calculation with an action (a button, when a field loses focus); do not calculate on every keystroke.
  • For the same inputs you can cache the result: results are deterministic for a given tool version, inputs and asOf. Include toolVersion and asOf in the cache key.
  • For bulk pulls (listAllTools), wait briefly between pages and store the results persistently.

If you send your request ID in X-Request-Id ([A-Za-z0-9._:-], 8–128 characters), it comes back unchanged in the response; this is useful for matching with your own logs.

For continuous, high-volume usage, contact us. Caching and using the widget are enough for most integrations without hitting the limits; since the widget does the calculation from the user’s browser, it spreads the load across users.