Skip to content

Rate Limits

Mayo ASPM enforces rate limits to ensure fair usage and platform stability. Limits vary by plan tier and endpoint type.


Limits by tier

Tier Requests per minute Requests per hour Concurrent scans
Free 60 1,000 1
Pro 300 10,000 5
Enterprise 1,000 50,000 20

Endpoint-specific limits

Some endpoints have additional limits beyond the per-tier rate:

Endpoint Limit Applies to
POST /api/scans 10 per hour (Free), 50 per hour (Pro), 200 per hour (Enterprise) Scan triggers
POST /api/tickets/generate 20 per hour Ticket generation
POST /api/auth/login 10 per minute Login attempts
POST /api/policies/evaluate 120 per minute Playground evaluations

Rate limit headers

Every API response includes rate limit headers:

HTTP/1.1 200 OK
X-RateLimit-Limit: 300
X-RateLimit-Remaining: 287
X-RateLimit-Reset: 1713168060
Header Description
X-RateLimit-Limit Maximum requests allowed in the current window
X-RateLimit-Remaining Requests remaining in the current window
X-RateLimit-Reset Unix timestamp when the window resets

When you're rate limited

If you exceed the limit, the API returns a 429 Too Many Requests response:

HTTP/1.1 429 Too Many Requests
Retry-After: 32
X-RateLimit-Limit: 300
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1713168060
Content-Type: application/json
{
  "error": {
    "code": "rate_limited",
    "message": "Rate limit exceeded. Retry after 32 seconds.",
    "retry_after": 32
  }
}

Handling rate limits

Check headers proactively

import requests
import time

def api_call(url, headers):
    response = requests.get(url, headers=headers)

    remaining = int(response.headers.get("X-RateLimit-Remaining", 0))
    if remaining < 10:
        reset_time = int(response.headers.get("X-RateLimit-Reset", 0))
        wait = max(reset_time - time.time(), 0)
        print(f"Rate limit nearly exhausted. Resets in {wait:.0f}s")

    return response

Retry with exponential backoff

import requests
import time

def api_call_with_retry(url, headers, max_retries=3):
    for attempt in range(max_retries):
        response = requests.get(url, headers=headers)

        if response.status_code != 429:
            return response

        retry_after = int(response.headers.get("Retry-After", 60))
        wait = retry_after * (2 ** attempt)
        print(f"Rate limited. Retrying in {wait}s (attempt {attempt + 1})")
        time.sleep(wait)

    raise Exception("Max retries exceeded")

Batch operations

Instead of making many individual requests, use bulk endpoints where available:

# Instead of: GET /api/findings/{id} x 100 times
# Use: GET /api/findings?id=f_1,f_2,f_3,...
curl "https://mayoaspm.com/api/findings?id=f_abc,f_def,f_ghi" \
  -H "Authorization: Bearer mayo_ak_..."

Rate limits by authentication type

Auth type Rate limit source
API Key Key's organization tier
JWT User's organization tier

Info

All API keys in the same organization share the organization's rate limit pool. If one key uses up the limit, all keys are affected.


Monitoring usage

View your API usage from Settings > Integrations > API Keys:

  • Requests in the last hour / day / month
  • Per-key usage breakdown
  • Rate limit hit count

Requesting higher limits

If your use case requires higher rate limits:

  • Pro tier users — upgrade to Enterprise
  • Enterprise tier users — contact support at support@mayoaspm.com for custom limits

Best practices

  1. Cache responses — avoid re-fetching data that hasn't changed.
  2. Use webhooks — instead of polling for scan completion, use the scan webhook callback.
  3. Batch requests — use filters and pagination instead of fetching one item at a time.
  4. Respect Retry-After — always wait the indicated time before retrying.
  5. Monitor your usage — set up alerts when approaching limits.

Next steps