Rate limits
So that one integration does not slow down all the others, DebtFlow limits the number of requests per minute. Every response shows how much headroom is left.
| Caller | Limit | Counted per |
|---|---|---|
| API key | 120 requests per minute | key |
| OAuth app | 120 requests per minute | connection (app and user) |
| Unauthenticated (e.g. token endpoint) | set per endpoint | IP address |
| All paths under /api/v1 combined | 1,000 requests per minute | IP address |
The per-IP limit applies in addition and only absorbs load peaks: if several keys run from the same server, they share these 1,000 requests. Individual resource-intensive endpoints may have their own, lower limit; the headers of each response are authoritative. The IP limit also responds with 429, error: "rate_limited" and Retry-After.
Headers
| Header | Meaning |
|---|---|
X-RateLimit-Limit | requests in the current time window |
X-RateLimit-Remaining | of which still remaining |
Retry-After | only with 429: seconds until the next attempt |
Response 429
HTTP/1.1 429 Too Many Requests
Retry-After: 17
X-RateLimit-Limit: 120
X-RateLimit-Remaining: 0
{ "error": "rate_limited", "message": "Too many requests. Please wait a moment.", "details": { "retryAfter": 17 } }Reacting correctly
On 429, wait at least as long as Retry-After specifies, then retry. For POST requests, use the same Idempotency-Key.
async function debtflow(path, init = {}, attempt = 0) {
const res = await fetch('https://www.debt-flow.io/api/v1' + path, {
...init,
headers: { ...init.headers, Authorization: `Bearer ${process.env.DEBTFLOW_API_KEY}` },
});
if (res.status === 429 && attempt < 5) {
const wait = Number(res.headers.get('Retry-After') ?? 1) * 1000;
await new Promise((r) => setTimeout(r, wait));
return debtflow(path, init, attempt + 1);
}
return res;
}Fewer requests rather than more speed
Instead of polling lists regularly, get notified by webhook. For bulk imports, use the page size
limit=100 and send requests one after another rather than in parallel.