Rate Limits & Quotas
Understand your usage limits and how to optimize your API requests.
Current Limits
| Limit Type | Value | Reset |
|---|---|---|
| Hourly requests | 10,000 | Top of each hour |
| Daily requests | 100,000 | Midnight UTC |
| Concurrent requests | 50 | Immediate |
These limits are generous for most use cases. If you need higher limits, please contact us.
What Counts as a Request?
Counts as 1 Request
- •Any API call (photos, rovers, cameras)
- •Regardless of page size (1-100 items)
- •Both successful and error responses
Does NOT Count
- •Requests that return 304 Not Modified
- •Fetching actual image files (NASA servers)
- •Health check endpoints
Rate Limit Headers
Every API response includes rate limit information in the headers:
HTTP/1.1 200 OK
X-RateLimit-Limit: 10000
X-RateLimit-Remaining: 9847
X-RateLimit-Reset: 1732580400| 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 limit resets |
Handling Rate Limit Errors
When you exceed a rate limit, you'll receive a 429 response:
{
"type": "/errors/rate-limit-exceeded",
"title": "Rate Limit Exceeded",
"status": 429,
"detail": "You have exceeded the hourly rate limit of 10000 requests.",
"retryAfter": 1523
}Implement exponential backoff to handle rate limits gracefully:
async function fetchWithRetry(url, options, maxRetries = 3) {
for (let attempt = 0; attempt < maxRetries; attempt++) {
const response = await fetch(url, options);
if (response.status === 429) {
const data = await response.json();
const waitTime = data.retryAfter || Math.pow(2, attempt) * 1000;
console.log(`Rate limited. Waiting ${waitTime}ms...`);
await new Promise(resolve => setTimeout(resolve, waitTime * 1000));
continue;
}
return response;
}
throw new Error('Max retries exceeded');
}Optimization Tips
1. Use Maximum Page Size
Request 100 items per page instead of the default 25 to reduce total API calls:
# Instead of this (4 requests for 100 items):
curl "...?per_page=25" # 4 requests needed
# Do this (1 request for 100 items):
curl "...?per_page=100" # 1 request2. Use HTTP Caching (ETags)
Cache responses and use conditional requests. 304 responses don't count against your limit:
// First request - store the ETag
const response = await fetch(url, { headers });
const etag = response.headers.get('ETag');
localStorage.setItem('etag', etag);
// Subsequent requests - use If-None-Match
const cachedEtag = localStorage.getItem('etag');
const response = await fetch(url, {
headers: { ...headers, 'If-None-Match': cachedEtag }
});
if (response.status === 304) {
// Use cached data - doesn't count as a request!
return cachedData;
}3. Request Only Needed Fields
Use field sets or custom field selection to reduce response size and processing time:
# Minimal response (faster)
curl "...?field_set=minimal"
# Or specific fields only
curl "...?fields=id,sol,images"4. Cache Static Data Locally
Rovers and cameras don't change often. Cache them locally:
// Fetch rovers once per day
async function getRovers() {
const cached = localStorage.getItem('rovers');
const cachedAt = localStorage.getItem('rovers_cached_at');
// Cache for 24 hours
if (cached && Date.now() - cachedAt < 86400000) {
return JSON.parse(cached);
}
const response = await fetch('/api/v2/rovers', { headers });
const data = await response.json();
localStorage.setItem('rovers', JSON.stringify(data));
localStorage.setItem('rovers_cached_at', Date.now());
return data;
}5. Use Batch Endpoints
Fetch multiple photos by ID in a single request:
# Instead of 10 separate requests:
curl ".../photos/1"
curl ".../photos/2"
# ...
# Use batch endpoint (1 request):
curl -X POST ".../photos/batch" \
-d '{"ids": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]}'Monitoring Your Usage
Track your usage by monitoring rate limit headers in your application:
async function trackUsage(response) {
const limit = response.headers.get('X-RateLimit-Limit');
const remaining = response.headers.get('X-RateLimit-Remaining');
const reset = response.headers.get('X-RateLimit-Reset');
const usedPercent = ((limit - remaining) / limit * 100).toFixed(1);
const resetTime = new Date(reset * 1000).toLocaleTimeString();
console.log(`API Usage: ${usedPercent}% (${remaining}/${limit} remaining)`);
console.log(`Resets at: ${resetTime}`);
// Alert when approaching limit
if (remaining < limit * 0.1) {
console.warn('WARNING: Approaching rate limit!');
}
}Next Steps
- Authentication →API key management and security
- Error Reference →Handle all error types