Rate limits and retries

120 reads, 30 writes and 10 e-invoicing operations per minute per credential, with X-RateLimit-* headers.

120 reads, 30 writes and 10 e-invoicing operations per minute per credential, with X-RateLimit-* headers.

← Back to the API documentation

Your first invoice in 6 steps

  1. Limits are per credential, per minute: 120 reads, 30 writes, 10 e-invoicing operations.
  2. The e-invoicing bucket covers efactura/submit, submissions/{id}/refresh and efactura/inbox/sync.
  3. Every response carries X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset, the 429 included.
  4. A 429 gives you Retry-After in seconds; wait that long before retrying.

What the 4invoices API is

http
HTTP/2 429
X-RateLimit-Limit: 30
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1785312000
Retry-After: 17
Content-Type: application/json

{"error":{"type":"rate_limit_error","code":"rate_limit_exceeded",
 "message":"...","doc_url":"https://4invoices.net/ro/api-dezvoltatori#errors",
 "request_id":"req_..."}}
javascript
// Honour Retry-After; never retry a 4xx other than 429.
async function call(url, init, attempt = 0) {
  const res = await fetch(url, init);
  if (res.status === 429 || res.status >= 500) {
    if (attempt >= 5) return res;
    const retryAfter = Number(res.headers.get("Retry-After")) || 2 ** attempt;
    await new Promise((r) => setTimeout(r, retryAfter * 1000));
    return call(url, init, attempt + 1);
  }
  return res;
}

// A write retry MUST reuse the SAME Idempotency-Key, otherwise you issue
// a second fiscal document.

https://api.4invoices.net/v1 · https://api.4invoices.net/v1/openapi.json

Rate limits

BucketRequests / minuteWhat it means
read120GET *, POST /invoices/preview-totals, POST /invoices/{id}/efactura/validate
write30POST /invoices, POST /invoices/{id}/storno, POST|DELETE /invoices/{id}/payments, POST /clients
submit10POST /invoices/{id}/efactura/submit, POST /efactura/submissions/{id}/refresh, POST /efactura/inbox/sync

Errors

StatusTypeCode
429rate_limit_errorrate_limit_exceeded

Common mistakes

  • The 10-per-minute bucket is not arbitrary: in Romania, ANAF itself allows roughly one message-list call per minute per CIF.
  • When retrying a write, reuse the SAME Idempotency-Key, otherwise you issue a second document.
  • The token endpoint has a separate per-IP limit. Cache the token for its full one-hour life.
  • GET /v1/me shows the credential's current buckets — useful in an integration health check.
  • Need higher ceilings? Write to us through the Contact page with your expected daily volume.

Developer questions and answers

Is the limit per account or per credential?

Per credential. Splitting traffic across per-system credentials means a bulk import cannot starve your shop's live flow.

What backoff do you recommend?

Honour Retry-After when present, otherwise exponential from 1–2 seconds with at most 5 attempts. No tight loops.

Does the 429 also carry the X-RateLimit headers?

Yes. We emit them on the 429 itself, which is exactly where a client needs them to compute the pause.