Nodaro Docs
DocumentationNode ReferenceModelsAI Agents (MCP)DevelopersSelf-hostingResearch
REST API

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 rateLimit on PATCH /v1/api-tokens/:id.
  • Only two routes count: POST /v1/api/run and GET /v1/api/workflows.
  • Reads do not count. GET /v1/api/status/:execId, GET /v1/api/result/:execId and GET /v1/api/schema do 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

RouteLimitAnswer when over
POST /v1/webhooks/:token (Webhook Trigger)10 requests per minute for each trigger429
A published app's runsThe app's daily run limit for each user429 rate_limit_exceeded
POST /v1/download-video4 video imports running at once for each account429 too_many_downloads
POST /v1/video-overlay30 requests per minute for each user429 rate_limit_exceeded
POST /v1/freecut-export10 requests per minute429 rate_limit_exceeded
POST /v1/characters/:id/train3 requests per minute for each token429 rate_limit_exceeded
POST /v1/oauth/register10 requests per minute for each IP address429 rate_limit_exceeded
POST /v1/orgsA few new organizations per hour for each user429 rate_limit_exceeded
POST /v1/workspaces/join10 attempts per minute for each account and 30 for each IP address429 rate_limit_exceeded
POST /v1/workflows/:id/collaborators20 additions per minute for each account429 rate_limit_exceeded
Usage exports as CSV10 per minute for each user429 rate_limit_exceeded
POST /v1/orgs/:id/invitations500 invitations a day for each organization429 bulk_invite_cap_exceeded
GET /v1/invitations/by-token/:token, GET /v1/shots/:id, the SSO sign-in exchangeA limit for each IP address429 rate_limit_exceeded

Two different 429 codes

  • rate_limited comes only from the per-token budget of the /v1/api/ routes.
  • rate_limit_exceeded comes 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/status and POST /v1/jobs/batch-status return up to 100 jobs each. See Jobs.
  • Back off exponentially on 429: wait 5 seconds, then 10, then 20, before each retry. When Retry-After is present, wait at least that long.
  • Treat other 4xx errors 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

EndpointLimit
GET /v1/jobs/status?ids=…Up to 100 ids
POST /v1/jobs/batch-statusUp to 100 ids
GET /v1/jobslimit up to 100
GET /v1/characterslimit up to 500, 100 by default
GET /v1/objects, /v1/creatures, /v1/locations, /v1/faceslimit up to 500
GET /v1/credits/transactionslimit from 1 to 50, 20 by default
POST /v1/credits/model-costsUp to 50 model ids
GET /v1/community/browselimit up to 50, 20 by default
GET /v1/orgs/:id/memberslimit up to 200, 50 by default
POST /v1/orgs/:id/invitationsUp to 200 addresses in one call
API tokens10 for each account
OAuth developer apps5 registered by hand for each user

Frequently asked questions

Last updated on

On this page