Rate limits and task quotas
Artguru applies call-rate limits and active-task quotas to protect the service from
retry storms and accidental overload. A rejected request returns HTTP 429 with
business code -1000 and does not consume credits.
Current limits
| Limit | Current value | Applies to |
|---|---|---|
| Calls per minute | 100 | Each API key |
| Calls per hour | 1,000 | Each API key |
| Active generation tasks | 3 | Each API key |
| Service-wide calls per minute | 10,000 | All API clients combined |
| Service-wide calls per hour | 50,000 | All API clients combined |
Every authenticated API call counts toward the call-rate windows, including image
uploads, task polling, and calls to GET /api/v1/usage. The active-task quota only
applies when creating a generation task. A task occupies a slot after it is accepted
and releases it when it reaches a terminal state.
Service-wide limits are protective ceilings shared by all clients, not capacity reserved for an individual account. Limits may change as the API evolves.
Inspect remaining call quota
Call GET /api/v1/usage to inspect the remaining per-key and service-wide call
quota. The request to /usage is itself counted before the returned values are
calculated.
The endpoint currently reports call-rate windows only. It does not report the number of active tasks or remaining active-task slots.
Handle 429 Too Many Requests
A quota rejection can include these response headers:
| Header | Meaning |
|---|---|
RateLimit-Limit | Limit for the scope that rejected the request. |
RateLimit-Remaining | Remaining capacity for that scope; normally 0 on rejection. |
RateLimit-Reset | Unix timestamp in seconds when the rejected scope is expected to reset. |
Retry-After | Minimum number of seconds to wait before retrying. |
RateLimit-Scope | The limit that rejected the request; see below. |
RateLimit-Scope is one of:
| Scope | Meaning |
|---|---|
api_key_minute | This API key reached its per-minute call limit. |
api_key_hour | This API key reached its per-hour call limit. |
global_minute | The shared service reached its per-minute call limit. |
global_hour | The shared service reached its per-hour call limit. |
api_key_active_tasks | This API key already has the maximum number of active generation tasks. |
When Retry-After is present, always honor it. If it is absent, use exponential
backoff with random jitter. Jitter is especially important when many workers share
a key, so they do not all retry at the same instant. For api_key_active_tasks,
continue polling the tasks you already have and submit a new task only after one
becomes terminal. Changing API keys is not a retry strategy.
For HTTP 503, honor Retry-After when present and use exponential backoff with
jitter. Do not retry 400 or 401 responses without first changing the invalid
request or credential.
X-Request-Id correlates logs but is not an idempotency key. If a generation
submission times out after reaching the server, immediately sending the same request
again can create a second task and consume credits again. Store the requestId and
returned taskId; retry a submission only when you know the first request was not
accepted.