Skip to main content

Rate limits

The API Connect limits the number of requests per API key in two simultaneous time windows.

The limits

WindowDefault limit
Per minute120 requests
Per hour5,000 requests

Both windows are evaluated on every request. If either is exceeded, the API responds with HTTP 429.

These are default values, sized for supermarkets and retail operations with multiple concurrent POS terminals. If your use case requires higher volumes (bulk batch issuance, intensive reporting), contact Ocote to adjust the limits of your key.

Why two windows

  • The per-minute window protects against accidental spikes — a runaway loop emitting thousands of invoices per second.
  • The per-hour window protects against sustained abuse and guarantees fair capacity across API clients.

A normal issuance flow (one invoice when a customer pays) never touches either.

Control headers

Every response from the API Connect (including errors) includes these headers:

HeaderDescription
X-RateLimit-Limit-MinuteYour per-minute limit. Ex: 120.
X-RateLimit-Limit-HourYour per-hour limit. Ex: 5000.
X-RateLimit-Remaining-MinuteRequests available in the current 60-s window.
X-RateLimit-Remaining-HourRequests available in the current 1-h window.
X-RateLimit-ResetSeconds until the minute window resets.

Real example:

HTTP/1.1 200 OK
Content-Type: application/json
X-RateLimit-Limit-Minute: 120
X-RateLimit-Limit-Hour: 5000
X-RateLimit-Remaining-Minute: 118
X-RateLimit-Remaining-Hour: 4982
X-RateLimit-Reset: 42

Read them from your client to pace yourself. If Remaining-Minute drops to 10, that's a good signal that you need to slow down.

When you exceed the limit

HTTP 429 with a Retry-After header indicating seconds:

HTTP/1.1 429 Too Many Requests
Content-Type: application/json
Retry-After: 18
X-RateLimit-Limit-Minute: 120
X-RateLimit-Remaining-Minute: 0
X-RateLimit-Reset: 18

{
"detail": "Limite de 120 requests por minuto excedido"
}

Rule: wait exactly Retry-After seconds before retrying. Any request before that will also receive 429.

Python (requests)
def request_with_backoff(method, url, **kwargs):
for _ in range(5):
r = requests.request(method, url, **kwargs)
if r.status_code == 429:
retry_after = int(r.headers.get("Retry-After", 60))
time.sleep(retry_after)
continue
return r
raise Exception("Rate limit not yielding after 5 attempts")
Node.js (axios)
async function requestWithBackoff(config) {
for (let i = 0; i < 5; i++) {
try {
return await axios(config);
} catch (err) {
if (err.response?.status === 429) {
const retry = parseInt(err.response.headers['retry-after'] || '60');
await new Promise(r => setTimeout(r, retry * 1000));
continue;
}
throw err;
}
}
throw new Error('Rate limit not yielding after 5 attempts');
}

What counts against the limit

Response typeCounts against limit?
HTTP 200 (success, MH rejection, contingency)Yes
HTTP 400 (invalid payload)Yes
HTTP 401 (invalid API key)No
HTTP 404 (document not found)Yes
HTTP 429 (rate limit)No
HTTP 500 (internal Ocote error)Yes

401s do not count because they require no API work and it would not make sense to rate-limit credential-stuffing attacks this way. 429s do not count because it would be contradictory.

Queries (GET /status/{id}, GET /file/{id}) count the same as issuances.

Best practices

Group polling. If you're monitoring N documents in contingency, do it once an hour reviewing all of them — not each document every minute. See Contingency > Responsible polling.

Do not retry 429 without waiting. An immediate retry on 429 does not speed anything up — it keeps you in 429.

Use Remaining-Minute to slow down proactively. If you drop below 10, insert a sleep(X-RateLimit-Reset + 1) before the next request.

Batch processing: if you need to emit 500 invoices in one shot, send them with ~500 ms pauses between each to stay well below 120/minute. At that pace you would take 4 minutes for the 500; if you try to go full-speed you end up waiting longer due to 429s.

Monitor headers in production. Dashboard X-RateLimit-Remaining-Hour from your responses to detect trends before they hit.

Non-numeric limits

Besides quantitative rate limiting, the API has qualitative payload limits:

  • lines[] per document: max 2,000 lines.
  • Line description: max 1,000 characters.
  • external_ref: max 100 characters.
  • Total JSON body length: max 5 MB.

These are enforced at validation (HTTP 400), not at rate limit. Exceeding any of them returns a payload error with specific detail.

See also