Rate Limits

    API requests are rate-limited based on your workspace's subscription tier. Rate limiting is enforced by AWS API Gateway Usage Plans.

    Tier Limits

    TierRequests / MinuteDaily Quota
    Free30Unlimited
    Starter60Unlimited
    Team300Unlimited
    Enterprise1,000Unlimited

    Every tier can create an API key, including free. What a key can do is what varies: a workspace an agent registered for itself has no calling capacity until a person verifies a mobile number for it. See registerWorkspace.

    Exceeding Limits

    When you exceed the per-minute request rate, the API returns 403 Forbidden, not 429. Rate limiting is enforced in the API Gateway authorizer, which can only deny with 403 and cannot send a Retry-After header, so there is nothing to wait on. A rate-limited 403 is indistinguishable from a scope denial: back off with jitter rather than treating it as permanent. The separate 429 is the concurrency ceiling — too many runs already in flight — and it does not carry a Retry-After either; wait for a run to finish.

    bash
    # A per-minute rate limit is refused by the API Gateway
    # authorizer, which can only deny with 403 and cannot attach a body
    # or a Retry-After header.
    curl -v -H "x-api-key: YOUR_API_KEY" \
      https://api.nopaque.co.uk/mapping
    
    # Response when rate limited:
    # HTTP/1.1 403 Forbidden
    #
    # Indistinguishable from a scope denial, so back off and retry
    # rather than treating it as permanent. There is no Retry-After
    # to wait on: use exponential backoff with jitter.

    Best Practices

    • Implement exponential backoff with jitter for retries
    • Cache responses when possible to reduce request volume
    • Use polling intervals of 5-10 seconds for status checks (avoid tight loops)
    • Contact support if you need higher limits for Enterprise tier

    Automatic retry in the SDKs

    The Nopaque SDKs auto-retry on 429 responses, honouring a Retry-After header when one is present and falling back to exponential jitter when it is not — which is the usual case, since this API does not send that header. Defaults: 3 retries with exponential jitter, capped at 8 seconds. You can tune or disable this behavior.

    They do not auto-retry the rate-limited 403, because a 403 is ordinarily a permanent scope or workspace denial and retrying it would be wrong. If you are driving the API hard enough to hit the per-minute limit, handle that back-off yourself.

    python
    from nopaque import Nopaque
    
    # Disable retries entirely
    client = Nopaque(max_retries=0)
    
    # Custom retry count + observability hook
    def log_retry(attempt, err, next_delay):
        print(f"attempt {attempt}: {type(err).__name__} → retrying in {next_delay:.1f}s")
    
    client = Nopaque(max_retries=5, on_retry=log_retry)
    
    # Per-call override
    job = client.mapping.get("map_abc123", request_options={"max_retries": 0})

    Important: POST requests that create or mutate state are only retried on 429 and pre-flight connection errors, never on 5xx or in-flight timeouts. This avoids duplicate side effects since the API does not support idempotency keys. If you need to retry a POST after a 5xx, call the method again yourself.