Skip to main content

Rate Limiting

SpatialFlow enforces rate limits to ensure fair usage and platform stability. Rate limiting operates at two layers: middleware-level (global, per-request) and decorator-level (per-endpoint).

Rate Limit Tiers

All API requests are subject to global rate limits based on the authentication method used:

AuthenticationLimitPeriodScope
API Key1,000 requestsPer hourPer key
JWT Token1,000 requestsPer hourPer token
Session (Admin)1,000 requestsPer hourPer user
Unauthenticated100 requestsPer hourPer IP

Endpoint-Specific Limits

Certain endpoints have stricter per-minute limits to prevent abuse:

EndpointLimitScope
Login5 requests per minutePer IP
Token Refresh10 requests per minutePer user
General API1,000 requests per hourPer API key

Rate Limit Headers

When a rate limit is exceeded, the API returns a 429 Too Many Requests response with the following headers:

HeaderDescription
Retry-AfterSeconds until the rate limit resets (per RFC 7231)
X-Quota-StatusQuota status when approaching limits (warning, alert, soft_throttle)
X-Quota-Usage-PercentCurrent event quota usage as a percentage

Example 429 response with headers:

HTTP/1.1 429 Too Many Requests
Content-Type: application/json
Retry-After: 3600
X-Request-ID: a1b2c3d4-e5f6-7890-abcd-ef1234567890

Rate Limit Response Format

When a global rate limit is exceeded, the API returns the following JSON body:

{
"detail": "Rate limit exceeded",
"error_code": "RATE_LIMIT_EXCEEDED",
"details": {
"limit": 1000,
"period_seconds": 3600
}
}

The details object includes the limit that was exceeded and the rate limit window in seconds.

Event Quota Throttling

In addition to request rate limits, SpatialFlow enforces event quotas based on your subscription plan. The quota system applies to tracked endpoints (device ingestion, geofence checks) and operates at these levels:

UsageStatusBehavior
< 100%OKNormal operation
100%WARNINGWarning headers added to responses
110%ALERTAlert headers added, notification email sent
120%SOFT_THROTTLERate limited to 50% capacity (429 responses)
150%HARD_CAPAll tracked requests blocked (403 responses)

When soft-throttled (120%), the response uses a different error code:

{
"detail": "Event quota exceeded (120%). Rate limited.",
"error_code": "RATE_LIMITED",
"retry_after": 60
}

When hard-capped (150%), the API returns a 403 Forbidden:

{
"detail": "Event quota exceeded (150%). Please upgrade your plan.",
"error_code": "QUOTA_EXCEEDED"
}
Upgrade Before Hitting the Hard Cap

Once your event usage reaches 150%, all tracked API requests are blocked entirely. Monitor the X-Quota-Usage-Percent header and upgrade your plan before reaching this threshold.

Handling Rate Limits

Check the Retry-After Header

Always read the Retry-After header from 429 responses before retrying. This header tells you exactly how many seconds to wait.

Implement Exponential Backoff

For transient rate limits, use exponential backoff with jitter to avoid thundering herd problems:

import time
import random
import requests

def call_api_with_retry(url, headers, max_retries=5):
"""Call the SpatialFlow API with automatic retry on rate limits."""
for attempt in range(max_retries):
response = requests.get(url, headers=headers)

if response.status_code != 429:
return response

# Use Retry-After header if available
retry_after = int(response.headers.get("Retry-After", 60))
# Add jitter to avoid thundering herd
jitter = random.uniform(0, retry_after * 0.1)
wait_time = retry_after + jitter

print(f"Rate limited. Retrying in {wait_time:.1f}s (attempt {attempt + 1})")
time.sleep(wait_time)

raise Exception("Max retries exceeded")

# Usage
response = call_api_with_retry(
"https://api.spatialflow.io/api/v1/geofences",
headers={"Authorization": "Bearer YOUR_API_KEY"},
)
Use the Retry-After Value

Do not guess how long to wait. The Retry-After header provides the exact number of seconds until your rate limit resets. Always prefer this value over a hardcoded delay.

Testing Rate Limits

You can observe rate limit behavior with a simple curl request:

# Send a request and inspect response headers
curl -i https://api.spatialflow.io/api/v1/geofences \
-H "Authorization: Bearer YOUR_API_KEY"

# When rate limited, you'll see:
# HTTP/1.1 429 Too Many Requests
# Retry-After: 3600
# Content-Type: application/json
#
# {"detail":"Rate limit exceeded","error_code":"RATE_LIMIT_EXCEEDED","details":{"limit":1000,"period_seconds":3600}}

Further Reading

  • Error Reference -- Full list of error codes including RATE_LIMIT_EXCEEDED and QUOTA_EXCEEDED
  • Best Practices -- Production patterns for retry logic and connection management