PlatformXeDocs
Get API Key

Rate Limits & Quotas

Understand and work within PlatformXe rate limits and plan quotas.

PlatformXe enforces per-route rate limits and per-plan monthly quotas. This guide covers how to work within these limits effectively.

Rate limit headers

When you approach or hit a rate limit, the response includes:

HeaderDescription
X-RateLimit-LimitMaximum requests allowed in the window
X-RateLimit-RemainingRequests remaining in the current window
X-RateLimit-ResetUnix timestamp when the window resets
Retry-AfterSeconds to wait before retrying (on 429 responses)

Rate-limited response

{
  "success": false,
  "error": {
    "code": "RATE_LIMITED",
    "message": "Rate limit exceeded. Retry after 45 seconds."
  }
}

Per-route limits

Route classLimit
Permission checks (check, resolve, check-batch)5,000/hr
Permission management (CRUD)500/hr
Audit queries and export100/hr
All other routes1,000/hr per API key

Strategies for staying within limits

Use batch endpoints

Instead of making 50 individual permission checks, use check-batch for up to 100 checks in a single request:

// Instead of this:
for (const action of actions) {
  await px.permissions.check({ adminId, path, action });
}

// Do this:
await px.permissions.checkBatch({
  adminId,
  checks: actions.map(action => ({ path, action })),
});

Cache resolved permissions

Use resolve to fetch a user's full capability set, then check locally:

const resolved = await px.permissions.resolve(userId);
const capabilities = new Set(resolved.data.capabilities);

// Check locally without API calls
function hasCapability(path: string, action: string): boolean {
  return capabilities.has(`${path}:${action}`);
}

Resolved permissions are cached server-side for 60 seconds. Client-side caching on top of this can eliminate the majority of permission check API calls.

Implement backoff on 429s

async function withBackoff<T>(fn: () => Promise<T>, maxRetries = 3): Promise<T> {
  for (let attempt = 0; attempt <= maxRetries; attempt++) {
    try {
      return await fn();
    } catch (err: any) {
      if (err.code === 'RATE_LIMITED' && attempt < maxRetries) {
        const retryAfter = err.retryAfter || Math.pow(2, attempt) * 1000;
        await new Promise(r => setTimeout(r, retryAfter));
        continue;
      }
      throw err;
    }
  }
  throw new Error('Max retries exceeded');
}

Monthly quotas by plan

ServiceFreeBasicProEnterprise
Emails50010,00050,000Custom
SMS501,0005,000Custom
Permission checks10,000100,000500,000Custom
Storage100 MB1 GB10 GBCustom

When a quota is exhausted, requests return QUOTA_EXCEEDED. Subscribe to billing.usage.threshold events to get warnings at 80% and 95%.

Rate limits are per API key, not per user. If multiple services share an API key, their requests count toward the same limit. Use separate API keys for different services when possible.