Skip to content

Developer portal

Rate limits & quotas

Layered limits protect shared infrastructure while keeping scan polling and auditor verify flows unblocked.

Last updated: 2026-07-01

Overview

Qtangl applies limits at several layers. Authenticated write routes share a per-key requests-per-minute budget. Authenticated read routes (including PQC scan polling) do not count toward that budget. Public verify, transparency, and Readiness Index routes use a separate per-IP limit. Signup and lead-capture forms have abuse caps. Discovery and remediation have additional tenant-scoped limits. Monthly scan caps are tier entitlements and return 402 Payment Required, not 429.

For authentication schemes and RBAC, see Authentication & RBAC. For key hygiene and transport security, see Security & compliance.

CategoryLimitScopeStatusNotes
Authenticated writes
QTANGL_RATE_LIMIT_PER_MINUTE
300 / minutePer API key or dashboard session429Minimum floor 300; Redis when REDIS_URL is set
Authenticated readsNo global counterPer API key429Polling GET /pqc/scan/{scanId} does not burn write budget
Public verify & transparency
QTANGL_VERIFY_RATE_LIMIT_PER_MINUTE
60 / minutePer client IP429Retry-After header on 429; in-memory per instance
Assess signup
QTANGL_ASSESS_SIGNUP_LIMIT_PER_HOUR
5 / hourPer email domain429—
Lead capture
QTANGL_LEAD_CAPTURE_LIMIT_PER_HOUR
10 / hourPer email domain429—
Discovery scan enqueue50 / hourPer tenant429Requires Redis
Discovery findings ingest10,000 / minutePer tenant + agent429Requires Redis
Monthly scan quotaTier-dependentPer tenant402Payment Required — not a rate limit
Crypto flip budget50 / dayPer tenantPolicyPolicy rejection; 24h KMS prod cooldown

Authenticated API — 300 req/min per key

The backend enforces 300 requests per minute per API key by default on authenticated write routes. Operators can override with QTANGL_RATE_LIMIT_PER_MINUTE; values below 300 are ignored. When REDIS_URL is set, counters are distributed across instances; otherwise each process keeps an in-memory sliding window.

Every response includes informational headers X-RateLimit-Limit and X-RateLimit-Window: 60. Rate-limit counter state uses a rolling 60-second window — see Data retention.

Routes under /admin/* use a separate admin key and are not counted. Unauthenticated health routes are unlimited.

Write routes (count toward limit)

MethodPathCounts toward 300/minNotes
POST/pqc/scanYesSupports Idempotency-Key
POST/pqc/upload-bundleYes—
POST/optimizeYes—
POST/tenant/discovery/host-scanYes—
POST/tenant/discovery/binary-scanYes—
POST/tenant/*YesWrite mutations (require_auth_write)

Read routes (exempt from global counter)

This exemption is intentional: polling GET /pqc/scan/{scanId} during a scan workflow does not consume your write budget.

MethodPathCounts toward 300/minNotes
GET/pqc/scan/{scanId}NoSafe for polling
GET/pqc/report/{scanId}No—
GET/pqc/inventoryNo—
GET/pqc/scenariosNo—
GET/tenant/scansNo—
GET/tenant/meNo—

Public endpoints — 60 req/min per IP

Verify, transparency log, Readiness Index, and dogfood routes are public — no API key required. They share a default limit of 60 requests per minute per client IP, keyed from X-Forwarded-For or the connection host. Override with QTANGL_VERIFY_RATE_LIMIT_PER_MINUTE and QTANGL_VERIFY_RATE_WINDOW_SEC. Responses include a Retry-After header on 429.

MethodPathNotes
GET/pqc/verify/{scanId}—
POST/pqc/verify—
GET/pqc/dogfood/latest—
GET/pqc/dogfood/summary—
GET/pqc/dogfood/history—
GET/pqc/dogfood/auditor-bundle—
GET/pqc/index—
GET/pqc/index/drift—
GET/pqc/transparency/consistency—
GET/pqc/transparency/witnesses—
POST/pqc/transparency/witness—
GET/pqc/transparency/root—
GET/pqc/transparency/keys—
GET/pqc/transparency/{contentHash}—

Signup and lead capture

Self-serve signup and marketing forms are rate-limited per email domain to reduce abuse.

CategoryLimitScopeStatusNotes
POST /public/assess-signup
QTANGL_ASSESS_SIGNUP_LIMIT_PER_HOUR
5 / hourPer email domain429Set <= 0 to disable
POST /public/lead-capture
QTANGL_LEAD_CAPTURE_LIMIT_PER_HOUR
10 / hourPer email domain429Set <= 0 to disable

Discovery limits

Host discovery scan enqueue and agent findings ingest have separate tenant-scoped limits. These require Redis; when Redis is unavailable, discovery rate limits are not enforced.

CategoryLimitScopeStatusNotes
Scan enqueue50 / hourPer tenant429POST /tenant/discovery/host-scan, POST /tenant/discovery/binary-scan
Findings ingest10,000 / minutePer tenant + agent429POST /discovery/agent/findings

Tier quotas (402, not 429)

Monthly scan counts, schedule caps, and API key limits are subscription entitlements. Exceeding a monthly scan quota returns 402 Payment Required with a scan_quota_exceeded code — not a rate limit. Production live scans also require legal acceptance and trial or paid status.

TierScans / monthSchedulesAPI keys
free501
monitor100105
convert5002510
enterprise5000100unlimited

Upgrade via the billing portal or pricing.

Remediation flip budget

Crypto flip automation enforces a policy budget of 50 flips per day per tenant, with a 24-hour cooldown between KMS production flips. Exceeding the budget returns a policy rejection in the response metadata — not HTTP 429.

429 and 402 responses

Per-key 429

HTTP/1.1 429 Too Many Requests
X-RateLimit-Limit: 300
X-RateLimit-Window: 60

{
  "detail": "Rate limit reached. The pilot API allows 300 requests per minute per key."
}
CodeMeaningTypical causeSuggested fix
429Too many requestsPer-key rate limit exceeded (default 300/min) or public endpoint IP limit (60/min).Backoff with jitter; poll read endpoints; cache results; contact support for production limits.
402Payment requiredMonthly scan quota or feature not included in current tier entitlements.Upgrade via billing portal or contact sales for enterprise tier.

Client patterns

  • Poll GET /pqc/scan/{scanId} freely — read routes are exempt from the 300/min write counter.
  • Send Idempotency-Key on POST /pqc/scan to avoid duplicate scans when retrying after 429 or network errors.
  • Exponential backoff with jitter on 429; respect Retry-After on public routes.
  • Official SDKs (TypeScript and Python) treat 429 as retryable with exponential backoff.
  • Cache optimize results when inputs have not changed.

Operator environment variables

VariableDefaultScope
QTANGL_RATE_LIMIT_PER_MINUTE300Per API key / session token, 60s window
QTANGL_VERIFY_RATE_LIMIT_PER_MINUTE60Per IP on public verify, transparency, and index routes
QTANGL_VERIFY_RATE_WINDOW_SEC60Window length for public IP limit
QTANGL_ASSESS_SIGNUP_LIMIT_PER_HOUR5Per email domain on assess signup
QTANGL_LEAD_CAPTURE_LIMIT_PER_HOUR10Per email domain on lead capture
REDIS_URLunsetEnables distributed per-key and discovery limits