Preskočiť na obsah

Errors and rate limits

Failed requests return a non-2xx status and a JSON error body with a stable code. Branch your code on the HTTP status and the code, never on the message text.

Every error has the same shape. code is a stable machine-readable string, message is written for humans in the language of the Accept-Language header (Slovak for sk or cs, otherwise English), and detail is optional extra data such as per-field validation errors or the name of the offending parameter.

{
"error": {
"code": "INVALID_PARAMETER",
"message": "limit must be between 1 and 100",
"detail": { "parameter": "limit" }
}
}
StatusCodesMeaning
400BAD_REQUEST, INVALID_PARAMETER, INVALID_CURSOR, UNSUPPORTED_FILTERThe request is malformed. Fix it before retrying.
401UNAUTHORIZEDKey missing, invalid, expired or revoked.
402PAYMENT_REQUIREDThe organization subscription is not active.
403FORBIDDEN, LEGACY_KEY_NOT_ALLOWEDMissing scope, or a legacy key on a v1-only endpoint.
404NOT_FOUNDThe resource does not exist in your organization.
409CONFLICT, IDEMPOTENCY_IN_PROGRESS, LIMIT_EXCEEDEDState conflict, a request with the same idempotency key is still running, or a plan limit was reached.
422VALIDATION_ERROR, IDEMPOTENCY_KEY_REUSED, TOKEN_OWNER_INACTIVE, WEBHOOK_URL_INVALID, WEBHOOK_URL_BLOCKED, UNKNOWN_EVENTThe request is well formed but cannot be processed.
429RATE_LIMITEDToo many requests. Wait for Retry-After.

Retry 429 after the time in Retry-After, and retry 5xx responses and network errors with exponential backoff. Do not retry other 4xx errors unchanged, because the same request will fail the same way. A 409 IDEMPOTENCY_IN_PROGRESS is safe to retry after a short pause. Always send an Idempotency-Key on POST requests you retry; see Idempotency.

Limits are counted per minute, once per API key and once per organization. The defaults are 120 requests per minute for a key and 600 for the whole organization, and they can differ per organization, so read the real values from limits.requests_per_minute and limits.org_requests_per_minute in GET /me. Limits are never keyed by IP address, so several organizations behind one egress address do not throttle each other.

Every response carries X-RateLimit-Limit (the ceiling of the tightest bucket), X-RateLimit-Remaining (requests left in the window) and X-RateLimit-Reset (seconds until the window resets). A 429 response adds Retry-After with the number of seconds to wait. Slow down before you reach zero by checking X-RateLimit-Remaining in a long-running job.

This helper honours Retry-After on 429, backs off exponentially on 5xx and network errors, and gives up after five attempts. It needs Node.js 18 or newer.

const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
export async function dakoty(path, init = {}, attempts = 5) {
const url = `https://api.dakoty.com/api/v1/public${path}`;
const headers = { Authorization: `Bearer ${process.env.DAKOTY_API_KEY}`, ...init.headers };
for (let i = 0; i < attempts; i++) {
let res;
try {
res = await fetch(url, { ...init, headers });
} catch (err) {
if (i === attempts - 1) throw err;
await sleep(2 ** i * 500);
continue;
}
if (res.status === 429 || res.status >= 500) {
if (i === attempts - 1) return res;
const wait = Number(res.headers.get("retry-after")) * 1000 || 2 ** i * 500;
await sleep(wait);
continue;
}
return res;
}
}

The same policy with requests. It re-sends the same Idempotency-Key header if you set it in headers, which is what makes retrying a POST safe.

import os
import time
import requests
BASE = "https://api.dakoty.com/api/v1/public"
def dakoty(method, path, attempts=5, **kwargs):
headers = {"Authorization": f"Bearer {os.environ['DAKOTY_API_KEY']}", **kwargs.pop("headers", {})}
for i in range(attempts):
try:
r = requests.request(method, BASE + path, headers=headers, timeout=30, **kwargs)
except requests.RequestException:
if i == attempts - 1:
raise
time.sleep(2**i * 0.5)
continue
if (r.status_code == 429 or r.status_code >= 500) and i < attempts - 1:
time.sleep(float(r.headers.get("Retry-After") or 2**i * 0.5))
continue
return r