Rate limits
A Nodaro API token allows 30 run requests per minute by default, up to 120. See the per-route limits, the two 429 codes, batch sizes and how to back off.
Rate limits protect the Nodaro API from bursts of requests. Each personal API token has its own per-minute budget for workflow runs, a few routes have limits of their own, and a request over a limit answers 429 Too Many Requests. Polling a job or a run never counts against a token's budget, so you can poll every few seconds without running out.
The per-token limit
Every personal API token has a budget of requests per minute:
- 30 requests per minute by default. You set the limit when you create the token, in Rate Limit (requests/min), from 1 to 120. Change it later with
rateLimitonPATCH /v1/api-tokens/:id. - Only two routes count:
POST /v1/api/runandGET /v1/api/workflows. - Reads do not count.
GET /v1/api/status/:execId,GET /v1/api/result/:execIdandGET /v1/api/schemado not use the budget. - The budget resets every minute.
A request over the budget answers:
{ "error": { "code": "rate_limited", "message": "Too many requests. Max 30 per minute." } }To go faster, raise the token's limit to 120. Beyond that, create more tokens, up to 10 per account, and spread your requests across them. See Authentication.
Other limits
| Route | Limit | Answer when over |
|---|---|---|
POST /v1/webhooks/:token (Webhook Trigger) | 10 requests per minute for each trigger | 429 |
| A published app's runs | The app's daily run limit for each user | 429 rate_limit_exceeded |
POST /v1/download-video | 4 video imports running at once for each account | 429 too_many_downloads |
POST /v1/video-overlay | 30 requests per minute for each user | 429 rate_limit_exceeded |
POST /v1/freecut-export | 10 requests per minute | 429 rate_limit_exceeded |
POST /v1/characters/:id/train | 3 requests per minute for each token | 429 rate_limit_exceeded |
POST /v1/oauth/register | 10 requests per minute for each IP address | 429 rate_limit_exceeded |
POST /v1/orgs | A few new organizations per hour for each user | 429 rate_limit_exceeded |
POST /v1/workspaces/join | 10 attempts per minute for each account and 30 for each IP address | 429 rate_limit_exceeded |
POST /v1/workflows/:id/collaborators | 20 additions per minute for each account | 429 rate_limit_exceeded |
| Usage exports as CSV | 10 per minute for each user | 429 rate_limit_exceeded |
POST /v1/orgs/:id/invitations | 500 invitations a day for each organization | 429 bulk_invite_cap_exceeded |
GET /v1/invitations/by-token/:token, GET /v1/shots/:id, the SSO sign-in exchange | A limit for each IP address | 429 rate_limit_exceeded |
Two different 429 codes
rate_limitedcomes only from the per-token budget of the/v1/api/routes.rate_limit_exceededcomes from every other limit: the limits for each IP address on a few routes that need no token, the limits for each caller on specific routes, and a published app's daily runs.
Routes with a limit for each caller send a Retry-After header. On a route that spends credits, the server answers 503 rate_limit_unavailable when it cannot check the limit.
Base your retry logic on the 429 status. Use the code only to tell the per-token budget from the other limits.
Handle limits well
- Poll every 2 to 5 seconds. A run changes state in seconds, and faster polling gains nothing.
- Poll many jobs in one call.
GET /v1/jobs/statusandPOST /v1/jobs/batch-statusreturn up to 100 jobs each. See Jobs. - Back off exponentially on
429: wait 5 seconds, then 10, then 20, before each retry. WhenRetry-Afteris present, wait at least that long. - Treat other
4xxerrors as final. Fix the request instead of retrying it. See Errors.
import { RateLimitedError } from '@nodaro/sdk'
async function withBackoff<T>(call: () => Promise<T>): Promise<T> {
for (const seconds of [5, 10, 20]) {
try {
return await call()
} catch (err) {
if (!(err instanceof RateLimitedError)) throw err
await new Promise((r) => setTimeout(r, seconds * 1_000))
}
}
return call()
}
const { executionId } = await withBackoff(() => client.workflows.run(workflowId))Batch and page sizes
| Endpoint | Limit |
|---|---|
GET /v1/jobs/status?ids=… | Up to 100 ids |
POST /v1/jobs/batch-status | Up to 100 ids |
GET /v1/jobs | limit up to 100 |
GET /v1/characters | limit up to 500, 100 by default |
GET /v1/objects, /v1/creatures, /v1/locations, /v1/faces | limit up to 500 |
GET /v1/credits/transactions | limit from 1 to 50, 20 by default |
POST /v1/credits/model-costs | Up to 50 model ids |
GET /v1/community/browse | limit up to 50, 20 by default |
GET /v1/orgs/:id/members | limit up to 200, 50 by default |
POST /v1/orgs/:id/invitations | Up to 200 addresses in one call |
| API tokens | 10 for each account |
| OAuth developer apps | 5 registered by hand for each user |
Frequently asked questions
Related
Authentication
Errors
Jobs
Webhooks
Workflows
Last updated on
Errors
Every Nodaro API error has an HTTP status and a stable code in one envelope. Learn what each code means, which errors to retry, and how failed jobs report why.
OpenAPI spec
Download the Nodaro OpenAPI 3.1 spec from /v1/openapi.json, see which endpoints it covers, and generate typed clients in Go, Rust, Python and other languages.