Rate Limiting
NeuralSnap uses rate limiting to ensure fair usage and protect the platform. Limits are applied per API key and vary by plan and endpoint. When you exceed a limit, the API returns a 429 Too Many Requests response with a retry_after value.
Rate Limit Headers
Every API response includes headers that tell you your current rate limit status. Use these to implement proactive throttling before hitting the limit.
| Property | Type | Description |
|---|---|---|
X-RateLimit-Limit | number | Maximum requests allowed in the current window. |
X-RateLimit-Remaining | number | Requests remaining in the current window. |
X-RateLimit-Reset | number | Unix timestamp (seconds) when the current window resets. |
Retry-After | number | Seconds to wait before retrying (only present on 429 responses). |
HTTP/1.1 200 OKX-RateLimit-Limit: 60X-RateLimit-Remaining: 42X-RateLimit-Reset: 1706097600Content-Type: application/json
Limits by Endpoint & Plan
Rate limits depend on the endpoint and your plan. AI-powered endpoints (crystallize, knowledge ingestion) have lower limits due to compute costs. Read endpoints are more generous.
| Endpoint | Plan | Rate | Burst |
|---|---|---|---|
| GET /snapshots | Free | 60 req/min | 10 req/s |
| GET /snapshots | Pro | 300 req/min | 30 req/s |
| POST /snapshots | Free | 30 req/min | 5 req/s |
| POST /snapshots | Pro | 120 req/min | 20 req/s |
| POST /crystallize | Free | 10 req/min | 2 req/s |
| POST /crystallize | Pro | 60 req/min | 10 req/s |
| GET/POST /memories/* | Free | 60 req/min | 10 req/s |
| GET/POST /memories/* | Pro | 300 req/min | 30 req/s |
| GET/POST /edges/* | Free | 60 req/min | 10 req/s |
| GET/POST /edges/* | Pro | 300 req/min | 30 req/s |
| POST /specific-knowledge/* | Free | 10 req/min | 2 req/s |
| POST /specific-knowledge/* | Pro | 60 req/min | 10 req/s |
| GET /snapshots/search | Free | 30 req/min | 5 req/s |
| GET /snapshots/search | Pro | 120 req/min | 20 req/s |
Need higher limits?
Best Practices
1. Check headers proactively
Monitor X-RateLimit-Remaining and slow down when it approaches zero. Don't wait for a 429 — that wastes a request.
2. Use exponential backoff
When you get a 429, respect the Retry-After header. If it's not present, use exponential backoff: wait 1s, then 2s, then 4s, up to 30s max.
3. Batch when possible
Instead of creating 10 snapshots in 10 separate requests, use the crystallize endpoint to extract multiple snapshots from a single text. One request, multiple results.
4. Cache search results
Search results don't change frequently. Cache responses for 30–60 seconds on your side to reduce unnecessary API calls.
Retry Implementation
async function fetchWithRetry(url, options, maxRetries = 3) {for (let attempt = 0; attempt <= maxRetries; attempt++) {const res = await fetch(url, options);if (res.status === 429) {const retryAfter = parseInt(res.headers.get("Retry-After") || "1");const backoff = Math.min(retryAfter, 30);console.log(`Rate limited. Retrying in ${backoff}s (attempt ${attempt + 1}/${maxRetries})`);await new Promise(r => setTimeout(r, backoff * 1000));continue;}return res;}throw new Error("Max retries exceeded");}// Usageconst res = await fetchWithRetry("https://api.neuralsnap.ai/v1/snapshots", {headers: { "Authorization": "Bearer ns_test_abc123" },});