Limits¶
This page documents all rate limits, size limits, and other constraints that apply to the Nodexa API.
Request Limits¶
Tools¶
| Limit | Value |
|---|---|
| Maximum tools per request | 128 |
| Maximum tool name length | 64 characters |
| Allowed tool name characters | Alphanumeric (a-z, A-Z, 0-9), underscore (_), hyphen (-) |
| Tool names must be unique | Yes — within a single request |
Tool names must match the pattern: ^[a-zA-Z0-9_-]{1,64}$
Examples:
get_weather— validlookup-order— validmyTool123— validmy tool— invalid (space not allowed)aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa— invalid (65 chars, exceeds limit)
Input¶
| Limit | Value |
|---|---|
| Maximum input messages in array | Subject to the backing LLM's context window |
Maximum instructions field length |
Subject to the backing LLM's context window |
Context window limits
Nodexa does not enforce its own token limits on input. However, the request will fail if the total token count exceeds the context window of the LLM model backing the active specialist agent. Token limits vary by provider and model (e.g., 128k tokens for GPT-4o, 200k for Claude 3.5 Sonnet). Contact your Nodexa administrator for the models in use on your instance.
User Claims Limits¶
| Limit | Value |
|---|---|
Maximum claimValue size |
64KB (as JSONB) |
| Maximum claims per bulk request | 50 |
| Number of claims per user | No enforced limit |
Memory Limits¶
| Limit | Value |
|---|---|
| Number of memory items per user/assistant pair | Managed by the platform — contact your administrator |
| Memory item content length | Subject to platform configuration |
API Key Limits¶
| Limit | Value |
|---|---|
| Keys per organization | Configured by your administrator |
| Key expiry | Keys do not expire automatically; must be explicitly revoked |
Rate Limits¶
Rate limits are configured per-organization by your Nodexa administrator and depend on your deployment tier. When you exceed a rate limit, the API returns 429 Too Many Requests.
{
"error": {
"type": "rate_limit_error",
"code": "rate_limit_exceeded",
"message": "You have exceeded the rate limit. Please wait before retrying."
}
}
The response includes a Retry-After header indicating how many seconds to wait:
Handling Rate Limits¶
async function callWithRateLimitRetry(fn, maxRetries = 5) {
for (let attempt = 0; attempt < maxRetries; attempt++) {
try {
return await fn();
} catch (err) {
if (err.status === 429) {
const retryAfter = parseInt(err.headers?.['retry-after'] ?? '1', 10);
console.warn(`Rate limited. Retrying in ${retryAfter}s...`);
await new Promise(r => setTimeout(r, retryAfter * 1000));
continue;
}
throw err;
}
}
throw new Error('Max retries exceeded');
}
Streaming Connection Limits¶
| Limit | Value |
|---|---|
| Heartbeat interval | 15 seconds (comment sent if no data for 15s) |
| Maximum stream duration | Subject to your platform's proxy/load balancer configuration |
Proxy and CDN timeouts
If your infrastructure uses a reverse proxy (Nginx, HAProxy) or CDN (Cloudflare, CloudFront), ensure idle connection timeouts are set higher than 15 seconds. The heartbeat is designed to keep connections alive for intermediaries with up to 15-second idle timeouts. If your proxy has a shorter timeout, configure it accordingly.
Bulk Operations¶
| Operation | Limit |
|---|---|
POST /v1/user-claims/bulk |
Maximum 50 claims per request |
For larger batches, split requests into chunks of 50:
async function bulkUpsertClaims(claims) {
const CHUNK_SIZE = 50;
for (let i = 0; i < claims.length; i += CHUNK_SIZE) {
const chunk = claims.slice(i, i + CHUNK_SIZE);
await fetch('/v1/user-claims/bulk', {
method: 'POST',
headers: {
'x-api-key': process.env.NODEXA_API_KEY,
'Content-Type': 'application/json',
},
body: JSON.stringify({ claims: chunk }),
});
}
}
Validation Reference¶
Tool Name Validation¶
// Check if a tool name is valid
function isValidToolName(name) {
return /^[a-zA-Z0-9_-]{1,64}$/.test(name);
}
isValidToolName('get_weather'); // true
isValidToolName('lookup-order'); // true
isValidToolName('my tool'); // false (space)
isValidToolName('a'.repeat(65)); // false (too long)
isValidToolName(''); // false (empty)