Limits & Quotas
DataRecs applies a few limits per tenant (your whole account, across every workspace) to keep the platform fast and fair for everyone. This page lists the limits you may encounter, the responses you’ll see when you reach one, and how a well-behaved integration should react. Limits depend on your plan — contact us if you need them raised.
Concurrent reconciliation runs
Section titled “Concurrent reconciliation runs”Your tenant can have a limited number of reconciliation runs in progress at once, across all workspaces combined (a run is “in progress” while it is queued or running, before it completes, errors, or is cancelled).
| Plan | Concurrent runs | Runs per day |
|---|---|---|
| Free | 2 | 25 |
| Standard | 10 | 500 |
If you trigger a run while you are already at the limit, the request is rejected — it is not queued — with HTTP 403 and this body:
{ "error_code": "QUOTA_EXCEEDED", "entitlement_key": "max_concurrent_runs", "limit": 2, "current": 2}entitlement_keytells you which limit you hit (max_concurrent_runsormax_runs_per_day).limitis your plan’s allowance;currentis your usage at the moment of rejection.
How to respond: wait for one of your in-progress runs to finish, then retry — or stagger your triggers. Poll run status (or subscribe to webhooks) to know when a slot frees up. If you consistently need more headroom, contact us to raise the limit.
Stuck runs are recovered automatically
Section titled “Stuck runs are recovered automatically”You don’t need to worry about a crashed or lost run silently holding a slot forever. If a run’s
underlying job dies without reporting back, DataRecs detects it and finalises the run as
ERRORED (or CANCELLED, if you had requested cancellation) with a clear reason — freeing the
concurrent-run slot. A dead run becomes a clearly-errored run you can re-trigger; it never sticks
in RUNNING indefinitely.
DataRecs will never report such a run as COMPLETED with no result behind it — if the result
was lost, the run is marked ERRORED so you know to re-run it, never given a misleading success.
API rate limits
Section titled “API rate limits”REST API requests are rate-limited per tenant. Your sustained request rate (requests per second) depends on your plan:
| Plan | API requests/second |
|---|---|
| Free | 5 |
| Standard | 50 |
A few endpoints have their own tighter limits (for example, triggering runs and authentication endpoints), independent of your plan rate.
When you exceed a rate limit you get HTTP 429 with a Retry-After header (seconds) and this
body:
{ "error_code": "RATE_LIMITED", "retry_after_seconds": 1, "message": "Rate limit exceeded. Please retry after the indicated delay."}How to respond: honour the Retry-After header — wait that many seconds, then retry. Add
exponential backoff with jitter for repeated 429s. A 429 means “slow down and try again
shortly”; it is not a permanent failure and does not mean you’ve hit a plan cap (that’s the
403 QUOTA_EXCEEDED above).
Request bodies are also bounded — an oversized request body is rejected. Keep individual API payloads small; use the bulk/list endpoints rather than very large single requests.
Result downloads
Section titled “Result downloads”Downloading the full result set of a reconciliation run is bounded so that a few large downloads don’t degrade the service.
Concurrency. Your tenant can run a small number of full-result downloads at once, across all
workspaces. If you start too many in parallel, the extra requests return HTTP 429 with a
Retry-After header:
{ "message": "Too many concurrent result downloads for this tenant (max 2). Retry shortly.", "retryAfterSeconds": 30}How to respond: download results sequentially rather than all at once; on a 429, wait for
Retry-After seconds and retry.
Size. A single full-result download is capped at 500 MB. A result set larger than that returns HTTP 413 (Payload Too Large) — use the API or CLI export for very large result sets, or narrow the run (filters, column selection) so each result is smaller.
CSV downloads: leading apostrophes
Section titled “CSV downloads: leading apostrophes”When you download reconciliation results as CSV, DataRecs protects you against
CSV formula injection: any text value
that begins with =, +, -, @, a tab, or a carriage return is exported with a leading single
quote (').
This means a spreadsheet (Excel, Google Sheets, …) treats the value as plain text instead of
executing it as a formula — so a malicious value like =HYPERLINK(...) smuggled into your source
data can’t run when you open the file.
What you’ll notice:
- A value such as
=SUM(A1:A9)appears as'=SUM(A1:A9)and displays as the literal text=SUM(A1:A9)(Excel shows the leading apostrophe only in the formula bar). - Numbers, dates, and booleans are untouched — only text columns are affected, and only when the text starts with one of those characters.
This protection is always on. If you need the raw, un-prefixed value, strip a single leading apostrophe from affected text cells after import.
Other limits
Section titled “Other limits”Your plan also caps your tenant’s total resources — connections, jobs, schedules, users, API keys,
and stored data. When you reach one of these you’ll get a 403 QUOTA_EXCEEDED naming the relevant
entitlement_key. Delete unused resources or contact us to raise the limit.
Webhook delivery has its own per-endpoint rate limit and retry behaviour — see Using Webhooks.
Summary
Section titled “Summary”| Limit | Response when exceeded | What to do |
|---|---|---|
| Concurrent runs / runs per day | 403 QUOTA_EXCEEDED | Wait for a run to finish, then retry; stagger triggers |
| API rate limit | 429 + Retry-After | Back off for Retry-After seconds; add jitter |
| Concurrent result downloads | 429 + Retry-After | Download sequentially; retry after the delay |
| Result download size (500 MB) | 413 Payload Too Large | Use API/CLI export or narrow the run |
| Resource counts (connections, jobs, …) | 403 QUOTA_EXCEEDED | Remove unused resources or contact us |
Need higher limits? Get in touch — most limits can be raised on a paid plan.