Limits and errors
AI rate limits, validation rules, the error response shape, and every error code you can hit.
Rate limits
Requests that start AI translation share one budget: the manual translation endpoint, single-cell recommendations, batch auto-translate, and adding a term or finishing an import with translate automatically on. Each request counts once, however many cells it translates. Adding terms or importing without automatic translation doesn't count. Sync jobs aren't rate-limited; the billing gate below applies to them.
| Limit | Value |
|---|---|
| Per organization | 200 AI requests per hour |
| Per user | 50 AI requests per hour |
Both must pass; exceeding either returns 429 TOO_MANY_REQUESTS. The
window is rolling — wait and retry.
Public-API translation reads are not rate-limited this way; they're metered as API usage for billing. See Platform → Limits for platform-wide quotas and where to see your current usage.
Billing gate
While your organization is blocked over unpaid invoices, these are
refused with 402 ORG_BLOCKED: creating a namespace or an API key,
starting a sync, and every request that starts AI translation (the ones
listed under rate limits above). A sync that was already accepted keeps
pushing your strings but skips AI translation and lists that in its
failures. Reads and other edits keep working. See
Platform → Billing → Dunning.
Validation rules
| Field | Rule |
|---|---|
| Namespace name | Letters, digits, hyphens, underscores (^[a-zA-Z0-9\-_]+$); unique per organization; case-sensitive. |
| Custom language code | Starts with a lowercase letter; lowercase letters, digits, hyphens, underscores; 1–32 chars; unique per organization; immutable. |
| Custom language name | 1–128 characters. |
| Term mark | Non-empty; unique per namespace. |
| Glossary item value / translation | Non-empty after trimming. |
| Custom prompt name / text | Non-empty. |
Error response shape
Every error is JSON with two fields:
{
"type": "INVALID_PAYLOAD",
"msg": "The payload is invalid."
}type is stable and meant for your code; msg is human-readable
detail that may change.
Error codes
| HTTP | type | Meaning |
|---|---|---|
| 400 | INVALID_PAYLOAD / INVALID_REQUEST | Malformed body or parameters — msg says what. |
| 400 | INVALID_NAME | A name field fails its validation rule (see above). |
| 400 | NO_TRANSLATION_SOURCE | AI translation requested for a term that has no non-empty value in any language — fill in the source first. |
| 400 | EMPTY_VALUE | A required value was empty. |
| 401 | INVALID_TOKEN | Session token missing, malformed, or expired. |
| 401 | UNAUTHORIZED | API key missing, revoked, or unrecognised; or the namespace isn't accessible. |
| 402 | ORG_BLOCKED | Organization blocked for unpaid invoices. |
| 403 | FORBIDDEN / INSUFFICIENT_PERMISSIONS | Authenticated, but you lack permission — including reading someone else's private custom prompt or a resource in another organization. |
| 404 | NOT_FOUND | The resource doesn't exist — including a glossary that hasn't been created yet. |
| 409 | CONFLICT | Duplicate: namespace name, term mark, custom language code, second glossary — or deleting a custom language still attached to a namespace. |
| 429 | TOO_MANY_REQUESTS | AI rate limit exceeded (see above). |
| 500 | INTERNAL_SERVER_ERROR | Unexpected server error — safe to retry with backoff. |
Behaviour during platform incidents
Live status: status.norcube.com. Reads are prioritised during degradation; background work (batch translation, sync jobs, imports) is resumable by design and picks up where it left off — see Sync jobs.