Skip to main content

Rate Limits

FieldValue
Document IDASCEND-API-006
Version1.0.0
Last UpdatedDecember 19, 2025
AuthorAscend Engineering Team
PublisherOW-KAI Technologies Inc.
ClassificationEnterprise Client Documentation
ComplianceSOC 2 CC6.1/CC6.2, PCI-DSS 7.1/8.3, HIPAA 164.312, NIST 800-53 AC-2/SI-4

Reading Time: 5 minutes | Skill Level: Intermediate

Overview

ASCEND implements rate limiting to ensure fair usage and system stability. Different endpoints have different limits based on their resource requirements.

Rate Limit Tiers

By Endpoint Category

CategoryLimitWindowBurst
Action Submission1,0001 minute50
Authentication51 minuteN/A
Read Operations5001 minute100
Analytics1001 minute20
Admin Operations501 minute10
Bulk Operations101 minute2

By Plan

PlanActions/minAPI Calls/minAgents
Starter10050010
Professional5002,00050
Enterprise2,00010,000Unlimited

Rate Limit Headers

Every response includes rate limit information:

HTTP/1.1 200 OK
X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 850
X-RateLimit-Reset: 1702656060
X-RateLimit-Window: 60
HeaderDescription
X-RateLimit-LimitMaximum requests allowed in window
X-RateLimit-RemainingRequests remaining in current window
X-RateLimit-ResetUnix timestamp when window resets
X-RateLimit-WindowWindow size in seconds

Rate Limit Response

When limits are exceeded:

HTTP/1.1 429 Too Many Requests
Retry-After: 45
Content-Type: application/json

{
"status": "error",
"error": {
"code": "RATE_LIMIT_EXCEEDED",
"message": "Rate limit exceeded. Retry after 45 seconds",
"details": {
"limit": 1000,
"window": "1m",
"current": 1005,
"retry_after": 45
}
}
}

Endpoint-Specific Limits

Action Submission

POST /api/v1/actions/submit
Limit: 1000/minute
Burst: 50 requests/second

Agent Registration

POST /api/registry/agents
Limit: 10/minute
Burst: 2 requests/second

Analytics Queries

GET /api/analytics/*
Limit: 100/minute
Burst: 20 requests/second

Authentication

POST /api/auth/*
Limit: 5/minute
No burst allowed

Handling Rate Limits

Python Example

import time
import requests
from typing import Optional

class RateLimitedClient:
def __init__(self, api_key: str, base_url: str = "https://pilot.owkai.app"):
self.api_key = api_key
self.base_url = base_url
self.session = requests.Session()
self.session.headers["X-API-Key"] = api_key

def request(self, method: str, path: str, **kwargs) -> requests.Response:
max_retries = 3

for attempt in range(max_retries):
response = self.session.request(
method,
f"{self.base_url}{path}",
**kwargs
)

if response.status_code == 429:
retry_after = int(response.headers.get("Retry-After", 60))
if attempt < max_retries - 1:
print(f"Rate limited. Waiting {retry_after}s...")
time.sleep(retry_after)
continue

return response

return response

def get_remaining_quota(self, response: requests.Response) -> dict:
return {
"limit": int(response.headers.get("X-RateLimit-Limit", 0)),
"remaining": int(response.headers.get("X-RateLimit-Remaining", 0)),
"reset": int(response.headers.get("X-RateLimit-Reset", 0))
}

# Usage
client = RateLimitedClient("owkai_...")
response = client.request("POST "https://pilot.owkai.app/api/v1/actions/submit", json={...})
quota = client.get_remaining_quota(response)
print(f"Remaining: {quota['remaining']}/{quota['limit']}")

Node.js Example

const axios = require('axios');

class RateLimitedClient {
constructor(apiKey) {
this.client = axios.create({
baseURL: 'https://pilot.owkai.app',
headers: { 'X-API-Key': apiKey }
});

this.client.interceptors.response.use(
response => response,
async error => {
if (error.response?.status === 429) {
const retryAfter = parseInt(error.response.headers['retry-after'] || 60);
console.log(`Rate limited. Waiting ${retryAfter}s...`);
await this.sleep(retryAfter * 1000);
return this.client.request(error.config);
}
throw error;
}
);
}

sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}

async submitAction(action) {
return this.client.post('/api/v1/actions', action);
}
}

// Usage
const client = new RateLimitedClient('owkai_...');
const response = await client.submitAction({
agent_id: 'my-agent',
action_type: 'data_read'
});

Rate Limit Best Practices

1. Implement Exponential Backoff

import time
import random

def exponential_backoff(attempt: int, base: float = 1.0, max_delay: float = 60.0):
delay = min(base * (2 ** attempt) + random.uniform(0, 1), max_delay)
time.sleep(delay)

2. Use Bulk Operations

Instead of:

# Bad: 100 individual requests
for item in items:
client.submit_action(item)

Use:

# Good: 1 bulk request
client.submit_actions_bulk(items)

3. Cache Responses

from functools import lru_cache

@lru_cache(maxsize=100, ttl=300)
def get_agent_details(agent_id: str):
return client.get(f"/api/agents/{agent_id}")

4. Monitor Usage

def check_rate_limit_status(response):
remaining = int(response.headers.get("X-RateLimit-Remaining", 0))
limit = int(response.headers.get("X-RateLimit-Limit", 1))

usage_percent = ((limit - remaining) / limit) * 100

if usage_percent > 80:
logger.warning(f"Rate limit usage at {usage_percent:.1f}%")

5. Distribute Load

import asyncio
import random

async def submit_with_jitter(actions):
for action in actions:
# Add random jitter to prevent thundering herd
await asyncio.sleep(random.uniform(0.01, 0.1))
await client.submit_action(action)

Rate Limit Exceptions

Enterprise Customers

Enterprise plans can request:

  • Increased limits
  • Dedicated rate limit pools
  • Priority queuing
  • Custom endpoint limits

Contact sales@owkai.app for custom limits.

Monitoring Rate Limits

Rate limit information is included in response headers. Monitor the X-RateLimit-Remaining header to track usage.

Set Up Alerts

curl -X POST "https://pilot.owkai.app/api/smart-rules" \
-H "Authorization: Bearer <admin_jwt>" \
-d '{
"name": "Rate Limit Warning",
"rule_definition": {
"condition_type": "threshold",
"metric": "rate_limit_usage_percent",
"operator": ">=",
"threshold": 80,
"severity": "medium"
}
}'

Next Steps


Document Version: 1.0.0 | Last Updated: December 2025