Skip to content

Rate Limiting

Rate limiting protects the Solatis API from abuse and ensures fair resource usage.

Understanding Rate Limits

Rate limits vary by plan and are applied per API key:

PlanRequests/MinuteRequests/DayConcurrent Requests
Individual6010,0005
Team300100,00025
EnterpriseCustomCustomCustom

Example:

  • Individual plan: 60 requests/minute means ~1 request per second
  • If you exceed this, requests are rate limited (HTTP 429)

Rate Limit Headers

Every API response includes rate limit information:

X-RateLimit-Limit: 60
X-RateLimit-Remaining: 45
X-RateLimit-Reset: 1643808000
HeaderMeaning
X-RateLimit-LimitMaximum requests/minute for your key
X-RateLimit-RemainingHow many requests left in current minute
X-RateLimit-ResetUnix timestamp when limit resets

Check Rate Limits Before Making Requests

JavaScript:

javascript
const checkRateLimit = async () => {
  const response = await fetch(
    'https://api.solatis.team/v2/documents',
    {
      headers: {
        'Authorization': 'Bearer YOUR_API_KEY'
      }
    }
  );

  const limit = response.headers.get('X-RateLimit-Limit');
  const remaining = response.headers.get('X-RateLimit-Remaining');
  const reset = response.headers.get('X-RateLimit-Reset');

  console.log(`Limit: ${limit}`);
  console.log(`Remaining: ${remaining}`);
  console.log(`Resets at: ${new Date(reset * 1000).toISOString()}`);

  return {
    limit: parseInt(limit),
    remaining: parseInt(remaining),
    resetAt: new Date(reset * 1000)
  };
};

Python:

python
import requests

response = requests.get(
    'https://api.solatis.team/v2/documents',
    headers={'Authorization': 'Bearer YOUR_API_KEY'}
)

limit = response.headers.get('X-RateLimit-Limit')
remaining = response.headers.get('X-RateLimit-Remaining')
reset = response.headers.get('X-RateLimit-Reset')

print(f'Limit: {limit}')
print(f'Remaining: {remaining}')
print(f'Resets at: {reset}')

Handling 429 Rate Limited Response

When rate limited, you receive HTTP 429:

json
{
  "error": {
    "code": "rate_limit_exceeded",
    "message": "Rate limit exceeded",
    "retry_after": 60
  }
}

The X-RateLimit-Reset header tells you when to retry.

Implement Exponential Backoff

JavaScript:

javascript
const makeRequestWithRetry = async (
  url,
  options,
  maxRetries = 5,
  baseDelay = 1000
) => {
  for (let attempt = 0; attempt < maxRetries; attempt++) {
    try {
      const response = await fetch(url, options);

      // Handle rate limiting
      if (response.status === 429) {
        const retryAfter = response.headers.get('X-RateLimit-Reset');
        const waitTime = (retryAfter * 1000) - Date.now();

        console.log(`Rate limited. Retrying in ${waitTime}ms...`);
        await new Promise(resolve => setTimeout(resolve, waitTime));
        continue;
      }

      if (!response.ok) {
        throw new Error(`HTTP ${response.status}`);
      }

      return await response.json();

    } catch (error) {
      if (attempt === maxRetries - 1) throw error;

      // Exponential backoff: 1s, 2s, 4s, 8s, 16s
      const delay = baseDelay * Math.pow(2, attempt);
      console.log(`Attempt ${attempt + 1} failed. Retrying in ${delay}ms...`);
      await new Promise(resolve => setTimeout(resolve, delay));
    }
  }
};

// Usage
const data = await makeRequestWithRetry(
  'https://api.solatis.team/v2/documents/analyze',
  {
    method: 'POST',
    headers: {
      'Authorization': 'Bearer YOUR_API_KEY',
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      document_url: 'https://example.com/contract.pdf'
    })
  }
);

Python:

python
import requests
import time
import math

def make_request_with_retry(
    url,
    method='GET',
    headers=None,
    json=None,
    max_retries=5,
    base_delay=1
):
    """Make request with exponential backoff retry"""

    for attempt in range(max_retries):
        try:
            if method == 'GET':
                response = requests.get(url, headers=headers)
            elif method == 'POST':
                response = requests.post(url, headers=headers, json=json)
            else:
                response = requests.request(method, url, headers=headers, json=json)

            # Handle rate limiting
            if response.status_code == 429:
                retry_after = int(response.headers.get('X-RateLimit-Reset', 60))
                wait_time = (retry_after * 1000) - (time.time() * 1000)

                print(f'Rate limited. Retrying in {wait_time}ms...')
                time.sleep(wait_time / 1000)
                continue

            response.raise_for_status()
            return response.json()

        except requests.exceptions.RequestException as e:
            if attempt == max_retries - 1:
                raise

            # Exponential backoff
            delay = base_delay * (2 ** attempt)
            print(f'Attempt {attempt + 1} failed. Retrying in {delay}s...')
            time.sleep(delay)

# Usage
data = make_request_with_retry(
    'https://api.solatis.team/v2/documents/analyze',
    method='POST',
    headers={'Authorization': 'Bearer YOUR_API_KEY'},
    json={'document_url': 'https://example.com/contract.pdf'}
)

Staying Within Limits

1. Track Your Usage

Monitor your API usage to avoid hitting limits:

javascript
const trackUsage = async (operation) => {
  const response = await fetch(
    'https://api.solatis.team/v2/documents',
    { headers: { 'Authorization': 'Bearer YOUR_API_KEY' } }
  );

  const remaining = parseInt(
    response.headers.get('X-RateLimit-Remaining')
  );

  const percentUsed = ((60 - remaining) / 60) * 100;
  console.log(`Rate limit usage: ${percentUsed.toFixed(1)}%`);

  // Log operation
  console.log(`[${operation}] Remaining requests: ${remaining}`);

  return remaining;
};

2. Batch Operations

Instead of making individual requests, batch them:

javascript
// ❌ BAD - Individual requests (uses 5 requests)
const documents = ['doc1', 'doc2', 'doc3', 'doc4', 'doc5'];
for (const doc of documents) {
  await client.documents.analyze(doc);
}

// ✅ GOOD - Batch request (uses 1 request)
const results = await client.documents.analyzeBatch(documents);

3. Cache Results

Cache API responses to avoid repeated requests:

javascript
const cache = new Map();
const CACHE_TTL = 5 * 60 * 1000; // 5 minutes

const getDocumentWithCache = async (docId) => {
  const cached = cache.get(docId);

  if (cached && Date.now() - cached.timestamp < CACHE_TTL) {
    console.log('Returning cached result');
    return cached.data;
  }

  const data = await client.documents.get(docId);
  cache.set(docId, {
    data,
    timestamp: Date.now()
  });

  return data;
};

4. Implement Request Queuing

Queue requests instead of making them all at once:

javascript
const pLimit = require('p-limit');

// Limit to 10 concurrent requests
const limit = pLimit(10);

const documents = [...]; // 1000 documents

const tasks = documents.map(doc =>
  limit(() => client.documents.analyze(doc))
);

const results = await Promise.all(tasks);

5. Schedule Batch Jobs

For large operations, use background jobs:

javascript
// Schedule job to run at off-peak hours
const schedule = require('node-schedule');

// Run at 2 AM every night
schedule.scheduleJob('0 2 * * *', async () => {
  console.log('Running batch analysis...');

  const allDocuments = await fetchAllDocuments();

  // Process in batches of 100
  for (let i = 0; i < allDocuments.length; i += 100) {
    const batch = allDocuments.slice(i, i + 100);
    await processBatch(batch);

    // Small delay between batches
    await new Promise(resolve => setTimeout(resolve, 1000));
  }
});

Monitoring and Alerts

Set Up Usage Alerts

Track current usage:

javascript
const monitorUsage = async () => {
  setInterval(async () => {
    const response = await fetch(
      'https://api.solatis.team/v2/documents',
      { headers: { 'Authorization': 'Bearer YOUR_API_KEY' } }
    );

    const limit = parseInt(response.headers.get('X-RateLimit-Limit'));
    const remaining = parseInt(response.headers.get('X-RateLimit-Remaining'));
    const used = limit - remaining;
    const percentUsed = (used / limit) * 100;

    console.log(`Usage: ${used}/${limit} (${percentUsed.toFixed(1)}%)`);

    // Alert if > 80% used
    if (percentUsed > 80) {
      sendAlert(`API rate limit usage: ${percentUsed.toFixed(1)}%`);
    }
  }, 60000); // Check every minute
};

Dashboard Integration

View API usage in your dashboard:

  1. Go to Settings → Developer → API Analytics
  2. See requests/minute, requests/day
  3. View breakdown by endpoint
  4. See peak usage times

Plan Upgrades

If you consistently hit rate limits, upgrade your plan:

ActionImpact
Individual → Team5x more requests/minute (60 → 300)
Team → EnterpriseCustom limits (unlimited)

Upgrade:

  1. Settings → Billing → Plans
  2. Click "Upgrade"
  3. Select new plan
  4. New limits apply immediately

Advanced Rate Limiting

Sliding Window

Solatis uses sliding window rate limiting:

Minute 0:00 - Requests: 0 (limit: 60)
Minute 0:30 - Requests: 40 (limit: 60) ✅ OK
Minute 0:45 - Requests: 60 (limit: 60) ✅ OK
Minute 1:00 - Request 61 (limit: 60) ❌ Rate limited!
Minute 1:15 - Requests: 55 (as old requests expire) ✅ Can continue

Request Weighting

Some endpoints consume more rate limit:

EndpointCost
GET /documents1 request
POST /documents/analyze5 requests (heavy computation)
POST /transcribe10 requests (complex processing)
GET /documents/:id1 request

Plan accordingly when using heavy endpoints.

Troubleshooting

Hitting Limits Too Quickly

Check:

  1. Are you polling too frequently?
  2. Are you making duplicate requests?
  3. Are you caching results?
  4. Should you batch operations?

Solutions:

  1. Increase time between requests
  2. Implement caching
  3. Use webhooks instead of polling
  4. Batch multiple operations

Uneven Rate Limit Usage

Issue: Using all requests at wrong times

Solution:

javascript
// Distribute requests evenly throughout minute
const delay = 60000 / requestsPerMinute; // e.g., 1000ms for 60 req/min
setInterval(makeRequest, delay);

Upgrading But Still Limited

Check:

  1. Is the new API key using upgraded plan?
  2. Did you update your code to use new key?
  3. Are there multiple keys hitting the limit?

Next Steps

Released under the MIT License.