Rate Limits

Understanding and working within clanker’s rate limits.

Overview

Rate limits protect the platform and ensure fair usage for all users.

API Rate Limits

Endpoint TypeLimitWindow
REST API100 requests1 minute
MCP tools60 requests1 minute
Skill execution30 requests1 minute

Rate Limit Headers

Every response includes rate limit information:

x-ratelimit-limit: 100
x-ratelimit-remaining: 45
x-ratelimit-reset: 60
HeaderDescription
x-ratelimit-limitMaximum requests per window
x-ratelimit-remainingRemaining requests in current window
x-ratelimit-resetSeconds until window resets

MCP Rate Limits

MCP tools are rate-limited to 60 requests per minute. Rate limit information is conveyed via HTTP response headers on the MCP transport endpoint (/mcp/), using the same x-ratelimit-* headers as the REST API.

Rate Limit Error

When you exceed the rate limit:

HTTP Response

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

{
  "error": {
    "type": "rate_limit_error",
    "message": "Rate limit exceeded. Retry after the x-ratelimit-reset window."
  }
}

Execution Limits

LimitValueDescription
Concurrent executions1 per workspaceOne execution runs per workspace at a time; a user can run executions in different workspaces concurrently
Execution timeout65 minutesMaximum execution duration
Input size100KBMaximum input payload size

Concurrent Execution Error

Returned with HTTP 429 when a workspace already has a running execution:

{
  "error": "EXECUTION_RUNNING",
  "message": "An execution is already running. Wait for it to complete."
}

Best Practices

1. Implement Exponential Backoff

async function fetchWithRetry(url, options, maxRetries = 3) {
  for (let attempt = 0; attempt < maxRetries; attempt++) {
    const response = await fetch(url, options);
    
    if (response.status === 429) {
      const resetIn = parseInt(response.headers.get('x-ratelimit-reset') || '60');
      const delay = resetIn * 1000 * Math.pow(2, attempt);
      console.log(`Rate limited. Waiting ${delay}ms...`);
      await new Promise(r => setTimeout(r, delay));
      continue;
    }
    
    return response;
  }
  
  throw new Error('Max retries exceeded');
}

2. Check Remaining Before Requests

let rateLimitRemaining = 60;
let rateLimitReset = Date.now();

async function makeRequest(url, options) {
  // Wait if no remaining requests
  if (rateLimitRemaining <= 0 && Date.now() < rateLimitReset) {
    const waitTime = rateLimitReset - Date.now();
    console.log(`Waiting ${waitTime}ms for rate limit reset...`);
    await new Promise(r => setTimeout(r, waitTime));
  }
  
  const response = await fetch(url, options);
  
  // Update rate limit info
  rateLimitRemaining = parseInt(response.headers.get('x-ratelimit-remaining') || '100');
  rateLimitReset = Date.now() + parseInt(response.headers.get('x-ratelimit-reset') || '60') * 1000;
  
  return response;
}

3. Cache Responses

const cache = new Map();
const CACHE_TTL = 60000; // 1 minute

async function cachedFetch(url, options) {
  const cacheKey = `${options?.method || 'GET'}:${url}`;
  const cached = cache.get(cacheKey);
  
  if (cached && Date.now() < cached.expiresAt) {
    return cached.data;
  }
  
  const response = await fetch(url, options);
  const data = await response.json();
  
  cache.set(cacheKey, {
    data,
    expiresAt: Date.now() + CACHE_TTL
  });
  
  return data;
}

5. Check Execution Status Before Starting

async function safeExecuteSkill(slug, input) {
  // Check if execution is already running
  const status = await getExecutionStatus();
  
  if (status?.status === 'running') {
    throw new Error('Please wait for current execution to complete');
  }
  
  return executeSkill(slug, input);
}

Rate Limits by Subscription

TierAPI RequestsMCP RequestsExecution Requests
Free100/min30/min
Pro100/min30/min
Based Mode100/min60/min30/min

Note: MCP access (60 req/min) is exclusive to Based Mode ($29/month). REST API rate limits are the same for all tiers.

Monitoring Usage

Check Rate Limit Status

curl -I https://clanker.net/api/v1/marketplace/skills \
  -H "x-api-key: YOUR_API_KEY"

Response headers show current usage:

x-ratelimit-limit: 100
x-ratelimit-remaining: 98
x-ratelimit-reset: 60

In Your Application

let apiCalls = 0;
const windowStart = Date.now();

// Log usage periodically
setInterval(() => {
  const elapsed = (Date.now() - windowStart) / 1000;
  console.log(`API calls: ${apiCalls} in ${elapsed}s`);
}, 30000);

Getting Help

If you consistently hit rate limits:

  1. Review your request patterns
  2. Implement caching and batching
  3. Check for request loops or bugs
  4. Contact support for usage optimization advice