Rate limits

Each API key may make 120 requests a minute. Every answer tells your program how many it has left, and a request over the limit is refused with the time to wait.

The limit

The limit belongs to the API key. Two keys of the same Business count apart, so a second program does not slow the first down. A Connected app has a limit of its own, counted the same way — one connected to the MCP server too, where every MCP request counts.

A minute starts with the key’s first request and ends 60 seconds later; the next request after that starts a new one. Every request the key makes in the minute counts, whatever it is answered — a request answered 404 for a record the Business does not have, or 422, costs what a success costs; an address the API has no endpoint for is answered 404 before the limit is counted, and costs nothing. A request with no key, or with an unknown or revoked one, is answered 401 and counts against no key.

The headers

Every answer to a request with a live API key or a Connected app’s access token carries three headers:

  • Name
    X-RateLimit-Limit
    Type
    integer
    Description

    How many requests the key or Connected app may make in a minute: 120.

  • Name
    X-RateLimit-Remaining
    Type
    integer
    Description

    How many it has left in this minute, the request just answered counted.

  • Name
    X-RateLimit-Reset
    Type
    integer
    Description

    When this minute ends and the count starts again, in Unix seconds (UTC).

An answer with 117 requests left

HTTP/2 200
Content-Type: application/json
X-RateLimit-Limit: 120
X-RateLimit-Remaining: 117
X-RateLimit-Reset: 1790503260

Over the limit

A request over the limit is answered 429 with an error of type rate_limit, and nothing is done: no record is read, created or changed. Retry-After says how many seconds to wait; send the request again after that.

The 121st request in a minute: 429

{
  "error": {
    "type": "rate_limit",
    "message": "This API key may make 120 requests a minute. Try again in 15 seconds."
  }
}

A program that walks a long list or imports many records should read X-RateLimit-Remaining and wait for X-RateLimit-Reset when it reaches 0, rather than meet the 429. A create sent again after a 429 is safe with or without an Idempotency-Key: the refused request created nothing.

Pacing a program

Wait for the next minute when none are left, and wait Retry-After seconds when a request is answered 429 anyway — by another process sharing the key, for instance:

A request that keeps to the limit

while :; do
  status=$(curl -s -D headers.txt -o clients.json -w '%{http_code}' https://api.essentio.pro/v1/clients \
    -H "Authorization: Bearer $ESSENTIO_API_KEY")
  [ "$status" != 429 ] && break
  sleep "$(grep -i '^Retry-After:' headers.txt | tr -dc 0-9)"
done

remaining=$(grep -i '^X-RateLimit-Remaining:' headers.txt | tr -dc 0-9)
reset=$(grep -i '^X-RateLimit-Reset:' headers.txt | tr -dc 0-9)
[ "$remaining" = 0 ] && sleep $((reset - $(date +%s) + 1))
echo "$status, $remaining left this minute"

The request log

Essentio records every request an API key or a Connected app makes, for 30 days: when it was made, which key or app made it (and, for an app, the person who connected it), the operation — its method and path, such as GET /v1/clients/{client}, or for the MCP server what it asked, such as mcp tools/call essentio_search_clients — the status it was answered and the IP address it came from. The Owner and the Admins of the Business read it in Essentio under Settings → API Keys, below the keys.

The log never holds what a request sent or what it was answered: no body, no Client, no document, and nothing of the address after the path — a search or any other parameter is not kept. After 30 days an entry is erased.