DynVoltDYNVOLT · developers

Rate limits

Per-token limits, the rate-limit headers, and backoff advice.

Rate limits are applied per token:

LimitValue
Requests per minute120
Requests per day5,000
Write requests per minute30

Writes (O&M actions, alert acknowledge/resolve, report runs, curtailment, BESS dispatch approvals) count against both the write limit and the overall limits.

Authentication throttle

Repeated authentication failures are throttled separately — 30 failed attempts per minute per source IP — to blunt brute-force scanning of the dvk_live_ keyspace. This is independent of the per-token limits above (a failed request has no valid token to bill). If you are looping on 401 unauthorized, fix the key rather than retrying; hammering the endpoint will get the source IP throttled.

Headers

Every response includes the current rate-limit state:

X-RateLimit-Limit: 120
X-RateLimit-Remaining: 87
X-RateLimit-Reset: 1754899200
  • X-RateLimit-Limit — the limit for the current window.
  • X-RateLimit-Remaining — requests left in the window.
  • X-RateLimit-Reset — Unix timestamp (seconds, UTC) when the window resets.

When you exceed a limit, the API returns 429 with error code rate_limited and a Retry-After header (seconds):

HTTP/1.1 429 Too Many Requests
Retry-After: 23

Backing off

  • Always honor Retry-After on 429 — it is the exact wait, no guessing needed.
  • For proactive throttling, watch X-RateLimit-Remaining and slow down before hitting zero.
  • For transient 5xx / upstream_unavailable errors, use exponential backoff with jitter (e.g. 1s, 2s, 4s, ... capped at 60s).
import random, time

def request_with_backoff(fn, max_attempts=6):
    for attempt in range(max_attempts):
        resp = fn()
        if resp.status_code == 429:
            time.sleep(int(resp.headers.get("Retry-After", "5")))
            continue
        if resp.status_code >= 500:
            time.sleep(min(2 ** attempt, 60) + random.random())
            continue
        return resp
    resp.raise_for_status()

Staying under the limits

  • Poll at the data's cadence. Live telemetry updates on the order of tens of seconds — polling /overview every 2 seconds burns budget for identical data. Once per minute is plenty for dashboards.
  • Prefer /overview over calling /loggers + /inverters + /sensors + /weather separately when you need the whole picture — one request instead of four.
  • Cache slow-moving data (site lists, report catalogs, markets metadata) for hours, not seconds.
  • Need more headroom for a legitimate use case? Contact DynVolt with your key ID and expected volume.