Rate Limits
Understanding RPM limits, concurrent thread limits, and how to handle them correctly
Limits Overview
MyDisct Solver API applies three separate protections. A request must pass all relevant checks before it can be accepted.
| Layer | What It Controls | Typical Error |
|---|---|---|
| IP limit | Too many requests from the same IP address in a short time | IP_RATE_LIMIT_EXCEEDED |
| API key RPM | How many requests your API key can send per minute | API_KEY_RATE_LIMIT_EXCEEDED |
| Concurrent threads | How many active solving tasks your subscription can run at the same time | THREAD_LIMIT_REACHED |
IP-Based Rate Limit
A global limit is applied per IP address to protect the service against abuse, DDoS traffic, and brute-force patterns. This check applies to every request, even before user-specific limits are evaluated.
| Scope | Limit | Window | Error Code |
|---|---|---|---|
| Per IP address | 1,000 requests | 1 minute | IP_RATE_LIMIT_EXCEEDED |
API Key RPM Limit
Each user has a personal RPM (Requests Per Minute) limit tied to the API key. Balance accounts default to 1,000 RPM. Subscription packages can include their own RPM values, and customizable packages can raise that limit further.
| Account Type | Default RPM | Notes |
|---|---|---|
| Balance account | 1,000 | Can be adjusted per user |
| Subscription package | Defined by package | Automatically applied when the subscription becomes active |
Concurrent Thread Limit
Threads are different from RPM. Threads control how many active captcha tasks can be processing at the same time on your account. If your package allows 2 threads, a third request can be rejected even if your RPM usage is still low.
When Threads Outside Billing is enabled on your subscription, requests above the package thread count are not blocked.
Instead, they continue with normal balance pricing and do not return THREAD_LIMIT_REACHED.
| Subscription Setting | When Threads Are Full |
|---|---|
| Disabled | New requests return THREAD_LIMIT_REACHED |
| Enabled | New requests continue with balance pricing |
Rate Limit Headers
Authenticated responses include RPM information in the headers. These headers describe request-per-minute usage, not concurrent thread usage.
X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 985
X-RateLimit-Reset: 45
| Header | Description |
|---|---|
X-RateLimit-Limit |
Your maximum requests allowed per minute |
X-RateLimit-Remaining |
Requests remaining in the current 1-minute window |
X-RateLimit-Reset |
Seconds until the RPM window resets |
429 Error Responses
All of the following situations may return HTTP 429 Too Many Requests, but the response body tells you which limit you hit.
IP Rate Limit Exceeded
{
"success": false,
"errorId": "ERROR_RATE_LIMIT",
"errorCode": "IP_RATE_LIMIT_EXCEEDED",
"message": "Too many requests from this IP address. Please wait before retrying.",
"service": "MyDisct Solver",
"retryAfter": 60
}
API Key RPM Exceeded
{
"success": false,
"errorId": "ERROR_RATE_LIMIT",
"errorCode": "API_KEY_RATE_LIMIT_EXCEEDED",
"message": "Rate limit exceeded. Your plan allows 1000 requests per minute.",
"service": "MyDisct Solver",
"rateLimit": {
"limit": 1000,
"remaining": 0,
"resetInSeconds": 42
}
}
Concurrent Thread Limit Reached
{
"success": false,
"service": "MyDisct Solver",
"error": {
"code": "THREAD_LIMIT_REACHED",
"message": "Your concurrent thread limit has been reached. Wait for an active task to finish before creating a new one."
},
"reason": "thread_limit_reached",
"thread_limit": 2,
"active_requests": 2
}
Checking Your RPM Limit
You can check your currently active RPM value with the /accountInfo endpoint.
{
"success": true,
"account": {
"email": "[email protected]",
"username": "myuser",
"balance": 25.50,
"currency": "USD",
"status": "active",
"rpm_limit": 1000,
"created_at": "2025-01-15T12:00:00.000Z"
}
}
Handling Limits
Handle each limit based on its cause. RPM errors should use retry logic. Thread errors should wait for active tasks to finish or rely on Threads Outside Billing.
async function solveWithRetry(captchaData, maxRetries = 3) {
for (let i = 0; i < maxRetries; i++) {
const response = await fetch('https://solver-api.mydisct.com/createTask', {
method: 'POST',
headers: {
apikey: 'YOUR_API_KEY',
'Content-Type': 'application/json'
},
body: JSON.stringify({
auth: { token: 'YOUR_API_KEY' },
context: { source: 'api', version: '1.0.0' },
captcha: captchaData
})
});
const data = await response.json();
if (response.status !== 429) {
return data;
}
if (data.errorCode === 'API_KEY_RATE_LIMIT_EXCEEDED') {
const resetSeconds = response.headers.get('X-RateLimit-Reset') || Math.pow(2, i) * 2;
await new Promise(resolve => setTimeout(resolve, resetSeconds * 1000));
continue;
}
if (data.error && data.error.code === 'THREAD_LIMIT_REACHED') {
throw new Error('Your active thread quota is full. Wait for a running task to finish.');
}
throw new Error(data.message || 'Rate limit exceeded');
}
throw new Error('Max retries reached');
}
Best Practices
- Monitor
X-RateLimit-Remainingto stay below your RPM ceiling - Use
X-RateLimit-Resetinstead of guessing retry timing - Treat
THREAD_LIMIT_REACHEDseparately from RPM errors in your client code - Use
thread_limitandactive_requeststo debug concurrency issues - Enable Threads Outside Billing if you want overflow traffic to continue with balance pricing
- Upgrade to packages with higher RPM or more threads if you hit limits consistently
- Avoid sending large request bursts when a steady flow is possible