Rate Limits

Understand API rate limiting and how to handle it. BlockSecOps API implements rate limiting to ensure fair usage and platform stability. Limits vary by plan....

Last updated: January 14, 2026

Rate Limits

Understand API rate limiting and how to handle it.

Overview

BlockSecOps API implements rate limiting to ensure fair usage and platform stability. Limits vary by plan.


Rate Limits by Plan

Plan Requests/Minute Requests/Hour Requests/Day
Free 10 100 500
Developer 60 1,000 10,000
Startup 120 5,000 50,000
Professional 300 Unlimited Unlimited
Enterprise Custom Custom Custom

Rate Limit Headers

Every API response includes rate limit information:

X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 950
X-RateLimit-Reset: 1705323600
Header Description
X-RateLimit-Limit Maximum requests allowed in window
X-RateLimit-Remaining Requests remaining in current window
X-RateLimit-Reset Unix timestamp when limit resets

Rate Limit Response

When you exceed the limit, you receive:

HTTP Status: 429 Too Many Requests

{
  "error": {
    "code": "RATE_LIMITED",
    "message": "Rate limit exceeded. Please retry after 45 seconds.",
    "retry_after": 45
  }
}

Headers:

Retry-After: 45
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1705323600

Handling Rate Limits

Check Before Hitting Limit

Monitor remaining requests:

const response = await fetch('/api/v1/scans', {
  headers: { 'Authorization': `Bearer ${apiKey}` }
});

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

if (remaining < 10) {
  console.log(`Low on requests. Resets at ${new Date(reset * 1000)}`);
}

Implement Exponential Backoff

async function apiCallWithRetry(url, options, maxRetries = 3) {
  for (let attempt = 0; attempt < maxRetries; attempt++) {
    const response = await fetch(url, options);

    if (response.status === 429) {
      const retryAfter = response.headers.get('Retry-After') || 60;
      const delay = retryAfter * 1000 * Math.pow(2, attempt);

      console.log(`Rate limited. Waiting ${delay}ms before retry.`);
      await new Promise(resolve => setTimeout(resolve, delay));
      continue;
    }

    return response;
  }

  throw new Error('Max retries exceeded');
}

Python Example

import time
import requests

def api_call_with_retry(url, headers, max_retries=3):
    for attempt in range(max_retries):
        response = requests.get(url, headers=headers)

        if response.status_code == 429:
            retry_after = int(response.headers.get('Retry-After', 60))
            delay = retry_after * (2 ** attempt)

            print(f"Rate limited. Waiting {delay}s before retry.")
            time.sleep(delay)
            continue

        return response

    raise Exception("Max retries exceeded")

Endpoint-Specific Limits

Some endpoints have additional limits:

Endpoint Additional Limit Notes
POST /contracts/upload 50/hour File upload limit
POST /scans Based on plan Scan concurrency limit
GET /scans/{id}/results 100/minute Result fetching
POST /webhooks 10/hour Webhook creation

Scan Concurrency Limits

Concurrent scan limits by plan:

Plan Concurrent Scans
Free 1
Developer 3
Startup 10
Professional 25
Enterprise Custom

When limit is reached:

{
  "error": {
    "code": "CONCURRENT_LIMIT",
    "message": "Maximum concurrent scans reached. Please wait for a scan to complete.",
    "current_scans": 3,
    "max_scans": 3
  }
}

Best Practices

Batch Operations

Instead of many individual requests, use batch endpoints:

# Instead of multiple individual uploads
# Use batch upload
curl -X POST "https://api.blocksecops.com/api/v1/contracts/upload" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -F "[email protected]"

Cache Results

Cache scan results locally to avoid repeated fetches:

const cache = new Map();

async function getScanResults(scanId) {
  if (cache.has(scanId)) {
    return cache.get(scanId);
  }

  const results = await fetchScanResults(scanId);
  cache.set(scanId, results);

  return results;
}

Use Webhooks

Instead of polling for scan completion, use webhooks:

# Start scan with webhook
curl -X POST "https://api.blocksecops.com/api/v1/scans" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "contract_id": "abc123",
    "webhook_url": "https://your-server.com/webhook"
  }'

Spread Requests

Space out non-urgent requests:

async function processContracts(contracts) {
  for (const contract of contracts) {
    await uploadContract(contract);

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

Rate Limit Exemptions

Enterprise customers can request:

  • Higher rate limits
  • Burst allowances for specific operations
  • Dedicated API endpoints
  • Custom rate limit windows

Contact support for Enterprise rate limit adjustments.


Monitoring Usage

Via Dashboard

Go to SettingsAPI Usage to see:

  • Requests per day/week/month
  • Top endpoints
  • Rate limit events
  • Usage trends

Via API

curl -X GET "https://api.blocksecops.com/api/v1/usage" \
  -H "Authorization: Bearer YOUR_API_KEY"

Response:

{
  "period": "2025-01",
  "requests": {
    "total": 15420,
    "by_endpoint": {
      "/scans": 5230,
      "/contracts": 3120,
      "/vulnerabilities": 7070
    }
  },
  "rate_limit_events": 3,
  "current_usage": {
    "minute": 45,
    "hour": 823
  }
}

Troubleshooting

Unexpected Rate Limiting

  1. Check all API keys: Multiple keys share org limits
  2. Review automated scripts: CI/CD may be making many calls
  3. Check for retry loops: Failed retries consume quota
  4. Monitor webhooks: Webhook failures trigger retries

Optimizing Usage

  1. Use efficient endpoints (batch operations)
  2. Cache frequently accessed data
  3. Implement proper retry logic with backoff
  4. Use webhooks instead of polling
  5. Review and optimize CI/CD scripts

Next Steps