Skip to main content

Rate Limits

CTWiseAPI enforces rate limits to ensure fair usage and service stability.

Rate Limit by Tier

TierRequests/SecondMonthly Calls
Free21,000
Starter1010,000

Response Headers

Every API response includes rate limit information:

HTTP/1.1 200 OK
X-RateLimit-Limit: 10
X-RateLimit-Remaining: 8
X-RateLimit-Reset: 1704067200
X-RateLimit-Monthly-Limit: 10000
X-RateLimit-Monthly-Remaining: 7500
HeaderDescription
X-RateLimit-LimitMax requests per second
X-RateLimit-RemainingRemaining requests in current second
X-RateLimit-ResetUnix timestamp when limit resets
X-RateLimit-Monthly-LimitMonthly call limit
X-RateLimit-Monthly-RemainingRemaining calls this month

Rate Limit Exceeded

When you exceed the rate limit:

HTTP/1.1 429 Too Many Requests
Retry-After: 1

{
"error": {
"code": "RATE_LIMIT_EXCEEDED",
"message": "Rate limit exceeded. Maximum 10 requests per second.",
"retryAfter": 1
}
}

Monthly Quota Exceeded

When you exceed monthly quota:

HTTP/1.1 429 Too Many Requests

{
"error": {
"code": "QUOTA_EXCEEDED",
"message": "Monthly API call limit reached. Upgrade your plan for more calls.",
"upgradeUrl": "https://app.orchestraprime.ai/ctwise/billing/upgrade"
}
}

Best Practices

Implement Exponential Backoff

import time
import requests
from requests.exceptions import RequestException

def make_request_with_backoff(url, headers, data, max_retries=3):
for attempt in range(max_retries):
try:
response = requests.post(url, headers=headers, json=data)

if response.status_code == 429:
retry_after = int(response.headers.get('Retry-After', 1))
wait_time = retry_after * (2 ** attempt) # Exponential backoff
print(f"Rate limited. Waiting {wait_time} seconds...")
time.sleep(wait_time)
continue

response.raise_for_status()
return response.json()

except RequestException as e:
if attempt == max_retries - 1:
raise
time.sleep(2 ** attempt)

raise Exception("Max retries exceeded")

Use Rate Limit Headers Proactively

async function makeRequest(url, options) {
const response = await fetch(url, options);

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

if (remaining < 2) {
// Slow down when approaching limit
await new Promise(resolve => setTimeout(resolve, 500));
}

return response.json();
}

Batch Requests When Possible

Instead of multiple single requests:

# ❌ Multiple requests
curl .../search -d '{"query": "informed consent"}'
curl .../search -d '{"query": "adverse events"}'
curl .../search -d '{"query": "data management"}'

Design your application to minimize API calls:

# ✅ Cache results
from functools import lru_cache

@lru_cache(maxsize=100)
def search_rules(query):
return api.search(query)

Monitor Usage

Check your usage regularly:

curl https://api.ctwise.ai/v1/usage \
-H "Authorization: Bearer YOUR_API_KEY"

Response:

{
"data": {
"tier": "starter",
"monthlyLimit": 10000,
"currentUsage": 2500,
"usagePercentage": 25,
"periodStart": "2025-01-01T00:00:00Z",
"periodEnd": "2025-01-31T23:59:59Z"
}
}

Set Up Usage Alerts

Configure alerts in your Dashboard:

  • 80% usage warning email
  • 90% usage warning email
  • 100% usage notification

FAQ

Why am I being rate limited?

Common causes:

  1. Too many concurrent requests
  2. No delay between requests
  3. Missing backoff logic on errors

Can I request higher limits?

For usage beyond 10,000 calls/month, contact sales@ctwise.ai for custom enterprise plans.

Do rate limits apply to test keys?

Yes, test keys have the same rate limits as live keys to ensure realistic testing.

Is there a burst allowance?

No burst allowance currently. Requests are measured on a per-second basis.