Rate Limiting
Silent Witness applies rate limits to ensure fair usage and service quality.
Request Limits
| Limit | Value |
|---|---|
| Requests per hour | 1,000 per API key |
| Window type | Sliding (not fixed hourly reset) |
File Upload Limits
| Constraint | Value |
|---|---|
| Maximum file size | 50MB per file |
| Supported image types | JPEG, PNG, GIF, WebP |
| Supported document types | |
| Empty files | Not allowed |
File type is detected from the file's bytes, not the Content-Type header your client sends.
Rate Limit Response
When you exceed the limit, the API returns 429 Too Many Requests:
{
"success": false,
"error": "Rate limit exceeded",
"error_code": "too_many_requests",
"error_type": "rate_limit_error",
"request_id": "req_abc123"
}
Handling Rate Limits
Implement exponential backoff when you receive a 429:
- Python
- TypeScript
- Go
import time
import requests
def api_request(method, path, max_retries=3, **kwargs):
for attempt in range(max_retries):
resp = requests.request(
method, f"{BASE_URL}{path}",
headers={"X-API-Key": API_KEY},
**kwargs,
)
if resp.status_code == 429:
delay = 2 ** attempt # 1s, 2s, 4s
print(f"Rate limited, retrying in {delay}s...")
time.sleep(delay)
continue
return resp
raise Exception("Max retries exceeded")
async function apiRequest(method: string, path: string, body?: object, maxRetries = 3) {
for (let attempt = 0; attempt < maxRetries; attempt++) {
const resp = await fetch(`${BASE_URL}${path}`, {
method,
headers: { "X-API-Key": API_KEY, "Content-Type": "application/json" },
body: body ? JSON.stringify(body) : undefined,
});
if (resp.status === 429) {
const delay = 2 ** attempt * 1000;
console.log(`Rate limited, retrying in ${delay / 1000}s...`);
await new Promise((r) => setTimeout(r, delay));
continue;
}
return resp;
}
throw new Error("Max retries exceeded");
}
func apiRequest(method, path string, body io.Reader, maxRetries int) (*http.Response, error) {
for attempt := 0; attempt < maxRetries; attempt++ {
req, _ := http.NewRequest(method, baseURL+path, body)
req.Header.Set("X-API-Key", apiKey)
resp, err := http.DefaultClient.Do(req)
if err != nil {
return nil, err
}
if resp.StatusCode == 429 {
delay := time.Duration(1<<attempt) * time.Second
log.Printf("Rate limited, retrying in %v...", delay)
time.Sleep(delay)
continue
}
return resp, nil
}
return nil, fmt.Errorf("max retries exceeded")
}
Best Practices
- Implement backoff — don't retry immediately after a 429
- Upload files in parallel — file uploads are independent and can run concurrently
- Cache responses — avoid re-fetching data you already have (e.g., case details)
- Use one key per application — separate keys have separate limits
- Contact support — request higher limits at support@silentwitness.ai if needed