Skip to main content
This page documents rate limiting on the DualEntry Public API (/public/v1/, /public/v2/), covering every endpoint authenticated with an X-API-KEY header. Limits are enforced per API key, not per user or per session, so two keys in the same organization draw on independent buckets even though they resolve the same limits. Requests are throttled to keep usage fair and the system stable. Limits use a token-bucket model with a fixed burst capacity and a continuous refill rate, so short spikes are absorbed up to your burst, and sustained traffic is capped at the refill rate. Nothing is queued: a request that arrives against an empty bucket is rejected immediately rather than held until a token frees up. Pace your calls using the headers described below rather than relying on the API to absorb a burst larger than your burst capacity.
V1 and V2 share the same rate-limit policy. The defaults, headers, and override mechanism described here apply to both versions of the Public API.

How limits are applied

Every request is checked against two independent token buckets: an org-wide aggregate bucket and a per-route bucket. The tighter of the two governs whether the request is admitted, so heavy traffic on a single endpoint is throttled by the per-route bucket even if your aggregate budget is healthy. The aggregate layer is checked first. If your key is over the aggregate budget, the per-endpoint layer is skipped, so you’ll get one 429 response, not two charges against your buckets.
Burst vs. refill: Burst is how many requests you can send back-to-back from a full bucket. Refill is how fast tokens replenish while you’re idle (or running below the limit). After exhausting your burst, you can keep going at the refill rate indefinitely.

Per-organization limits

Defaults apply to every organization out of the box, but limits can be raised per organization:
  • An organization-wide override for the aggregate or endpoint default
  • Targeted overrides for individual endpoints (for example, raise POST /v2/invoices/ while leaving everything else on defaults)
Overrides resolve from most specific to least specific. A targeted override for the exact method and route wins; failing that, your organization’s endpoint default applies; failing that, the platform default in the table above applies. The aggregate layer resolves the same way, with only an organization-wide value to fall back on. Raising the aggregate budget alone will not help a workload that hammers a single route, because the per-endpoint bucket is evaluated independently. If you have a high-volume integration (bulk imports, sync jobs, batch reconciliation), contact your administrator. Your organization’s limits can be extended to match real usage rather than asking you to adjust to the defaults.

Reading the response

Every response carries headers describing your current state, and any throttled request returns a structured 429. Together these tell you which bucket is binding and how long to wait before retrying.

Rate limit headers

Each response includes headers reflecting your tightest current bucket: when the per-endpoint bucket is closer to empty than the aggregate, the headers reflect the endpoint bucket, and vice versa. One set of headers always tells you which constraint will bite first.

Throttled responses

Once any bucket is empty, the API returns 429 Too Many Requests:
The response includes a Retry-After header (seconds) telling you exactly how long to wait before the bucket refills enough for one more request.

Best practices

Rate-limit-friendly clients share a few habits. Apply these when designing or tuning an integration so you stay well clear of 429s in steady state, and degrade gracefully when you do hit one. The first three are about avoiding the limit; the last two are about recovering once you’ve hit it.
  • Watch X-RateLimit-Remaining and back off before you hit zero
  • Cache master data (accounts, items, vendors), which rarely changes; uncached lookups are the most common cause of avoidable traffic
  • Spread traffic over time instead of bursting; the refill rate is the real ceiling for sustained workloads
  • Honor Retry-After on 429 responses, with exponential backoff for repeated failures. The header reports when one token will be available, not when the bucket is full, so a single retry at that interval buys you a single request
  • For hot endpoints (one route you call constantly), request a per-endpoint override instead of a blanket increase, since the per-endpoint layer is what’s binding, not the aggregate

Increasing your limit

If the defaults don’t fit your workload:
  1. Check X-RateLimit-Limit and X-RateLimit-Remaining to confirm which layer (aggregate vs. endpoint) is binding
  2. Eliminate any obviously redundant calls (uncached lookups, polling, retries on success)
  3. Contact your administrator with the affected endpoint(s) and target throughput, expressed as sustained requests per minute rather than a burst figure, since the refill rate governs steady-state throughput
  4. For separate workloads on the same org, consider issuing distinct API keys so a batch job doesn’t starve interactive traffic
Your organization’s limits can be extended globally or per endpoint. Endpoint overrides are validated against the live route list when they are saved, so an override naming a path that does not exist, or naming it with the wrong method, is rejected rather than silently ignored. Quote the method and path exactly as they appear in the API reference.
Next: Learn about Pagination →
Last modified on August 27, 2026