Appearance
Rate Limits
The InvoisX API implements rate limiting to ensure fair usage and system stability.
Default Limits
| Limit Type | Limit | Window |
|---|---|---|
| API Requests | 60 requests | Per minute |
| Document Submissions | Based on plan | Per month |
Rate Limit Headers
Every API response includes rate limit information:
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 45
X-RateLimit-Reset: 1704067200| Header | Description |
|---|---|
X-RateLimit-Limit | Maximum requests allowed |
X-RateLimit-Remaining | Requests remaining in window |
X-RateLimit-Reset | Unix timestamp when limit resets |
Rate Limit Exceeded
When you exceed the rate limit:
Response (HTTP 429):
json
{
"success": false,
"message": "Too many requests. Please try again in 60 seconds.",
"error_code": "RATE_LIMIT_EXCEEDED"
}Headers:
Retry-After: 60
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1704067200Handling Rate Limits
JavaScript
javascript
async function apiWithRetry(method, endpoint, data, maxRetries = 3) {
for (let attempt = 1; attempt <= maxRetries; attempt++) {
try {
return await api(method, endpoint, data);
} catch (error) {
if (error.response?.status === 429) {
const retryAfter = error.response.headers['retry-after'] || 60;
console.log(`Rate limited. Retrying in ${retryAfter}s...`);
await new Promise(r => setTimeout(r, retryAfter * 1000));
} else {
throw error;
}
}
}
throw new Error('Max retries exceeded');
}Python
python
import time
def api_with_retry(method, endpoint, data=None, max_retries=3):
for attempt in range(max_retries):
try:
return api(method, endpoint, data)
except RateLimitError as e:
retry_after = e.retry_after or 60
print(f'Rate limited. Retrying in {retry_after}s...')
time.sleep(retry_after)
raise Exception('Max retries exceeded')PHP
php
function apiWithRetry($api, $method, $endpoint, $data = null, $maxRetries = 3) {
for ($attempt = 1; $attempt <= $maxRetries; $attempt++) {
$response = $api->$method($endpoint, $data);
if ($response->status() !== 429) {
return $response;
}
$retryAfter = $response->header('Retry-After') ?: 60;
echo "Rate limited. Retrying in {$retryAfter}s...\n";
sleep($retryAfter);
}
throw new Exception('Max retries exceeded');
}Document Quota
In addition to API rate limits, document submissions are limited by your subscription plan:
| Plan | Monthly Quota |
|---|---|
| Starter | 100 documents |
| Professional | 500 documents |
| Business | 2,000 documents |
| Enterprise | Unlimited |
Checking Quota
The submission endpoint returns quota information:
json
{
"success": false,
"message": "Document quota exceeded. You have 0 documents remaining out of 100.",
"error_code": "QUOTA_EXCEEDED",
"errors": {
"quota": {
"used": 100,
"limit": 100,
"remaining": 0,
"resets_at": "2024-02-01T00:00:00+08:00"
}
}
}Best Practices
1. Implement Exponential Backoff
javascript
async function apiWithBackoff(method, endpoint, data) {
const delays = [1000, 2000, 4000, 8000];
for (let i = 0; i < delays.length; i++) {
try {
return await api(method, endpoint, data);
} catch (error) {
if (error.response?.status === 429 && i < delays.length - 1) {
await new Promise(r => setTimeout(r, delays[i]));
} else {
throw error;
}
}
}
}2. Queue Requests
For bulk operations, queue requests to stay within limits:
javascript
class RequestQueue {
constructor(requestsPerMinute = 60) {
this.queue = [];
this.processing = false;
this.delay = (60 / requestsPerMinute) * 1000;
}
async add(fn) {
return new Promise((resolve, reject) => {
this.queue.push({ fn, resolve, reject });
this.process();
});
}
async process() {
if (this.processing) return;
this.processing = true;
while (this.queue.length > 0) {
const { fn, resolve, reject } = this.queue.shift();
try {
resolve(await fn());
} catch (e) {
reject(e);
}
await new Promise(r => setTimeout(r, this.delay));
}
this.processing = false;
}
}
// Usage
const queue = new RequestQueue(50); // 50 requests per minute
const results = await Promise.all(
documentIds.map(id =>
queue.add(() => api('POST', `/documents/${id}/validate`))
)
);3. Cache Reference Data
Reference data endpoints (states, countries, etc.) rarely change. Cache them:
javascript
let statesCache = null;
let statesCacheTime = 0;
const CACHE_TTL = 3600000; // 1 hour
async function getStates() {
const now = Date.now();
if (!statesCache || now - statesCacheTime > CACHE_TTL) {
statesCache = await api('GET', '/states');
statesCacheTime = now;
}
return statesCache;
}4. Batch Operations
Use bulk endpoints where available:
javascript
// Instead of:
for (const id of documentIds) {
await api('POST', `/documents/${id}/submit`);
}
// Use:
await api('POST', '/documents/submit-bulk', {
document_ids: documentIds
});Need Higher Limits?
Contact us for custom rate limits and enterprise pricing:
- Email: support@invoisx.com
- Dashboard: Settings > Billing > Upgrade
