mirror of
https://github.com/mintlify/docs.git
synced 2026-09-14 13:35:46 +08:00
65fd3621dc
- Created 111 MDX documentation files - Added 89 API endpoint pages across 14 categories - Included 11 concept guides and 7 tutorials - Configured Mintlify with Spotify branding (#1DB954) - All pages validated successfully
260 lines
6.0 KiB
Plaintext
260 lines
6.0 KiB
Plaintext
---
|
|
title: "Rate limits"
|
|
description: "Understanding rate limiting in the Spotify Web API"
|
|
---
|
|
|
|
# Rate limits
|
|
|
|
The Spotify Web API uses rate limiting to protect service stability and ensure fair usage across all applications. Understanding and respecting these limits is crucial for building reliable applications.
|
|
|
|
## How rate limiting works
|
|
|
|
Rate limits restrict the number of API requests your application can make within a specific time window. When you exceed the limit, the API returns a 429 (Too Many Requests) error.
|
|
|
|
### Rate limit factors
|
|
|
|
Limits depend on:
|
|
- The specific endpoint being called
|
|
- Your app's quota mode (development vs extended)
|
|
- The authentication method used
|
|
- Current system load
|
|
|
|
<Note>
|
|
Rate limits are subject to change. Always implement adaptive rate limiting in your application.
|
|
</Note>
|
|
|
|
## Rate limit headers
|
|
|
|
Every API response includes headers with rate limit information:
|
|
|
|
<ResponseField name="X-RateLimit-Limit" type="integer">
|
|
The rate limit ceiling for the given endpoint
|
|
</ResponseField>
|
|
|
|
<ResponseField name="X-RateLimit-Remaining" type="integer">
|
|
Number of requests remaining in the current window
|
|
</ResponseField>
|
|
|
|
<ResponseField name="X-RateLimit-Reset" type="integer">
|
|
Time when the rate limit window resets (Unix timestamp)
|
|
</ResponseField>
|
|
|
|
Example response headers:
|
|
|
|
```
|
|
X-RateLimit-Limit: 100
|
|
X-RateLimit-Remaining: 73
|
|
X-RateLimit-Reset: 1612137600
|
|
```
|
|
|
|
## Handling rate limit errors
|
|
|
|
When you receive a 429 error, the response includes a `Retry-After` header:
|
|
|
|
```json
|
|
{
|
|
"error": {
|
|
"status": 429,
|
|
"message": "API rate limit exceeded"
|
|
}
|
|
}
|
|
```
|
|
|
|
Response headers:
|
|
```
|
|
Retry-After: 30
|
|
```
|
|
|
|
This indicates you should wait 30 seconds before retrying.
|
|
|
|
### Retry strategy
|
|
|
|
Implement exponential backoff with jitter:
|
|
|
|
```javascript
|
|
async function makeRequestWithRetry(url, token, maxRetries = 3) {
|
|
for (let i = 0; i < maxRetries; i++) {
|
|
const response = await fetch(url, {
|
|
headers: { 'Authorization': `Bearer ${token}` }
|
|
});
|
|
|
|
if (response.status !== 429) {
|
|
return response;
|
|
}
|
|
|
|
// Rate limited
|
|
const retryAfter = response.headers.get('Retry-After');
|
|
const waitTime = retryAfter ?
|
|
parseInt(retryAfter) * 1000 :
|
|
Math.pow(2, i) * 1000; // Exponential backoff
|
|
|
|
// Add jitter
|
|
const jitter = Math.random() * 1000;
|
|
await new Promise(resolve => setTimeout(resolve, waitTime + jitter));
|
|
}
|
|
|
|
throw new Error('Max retries exceeded');
|
|
}
|
|
```
|
|
|
|
## Best practices
|
|
|
|
<AccordionGroup>
|
|
<Accordion title="Monitor rate limit headers">
|
|
Track `X-RateLimit-Remaining` and proactively slow down requests when approaching the limit.
|
|
|
|
```javascript
|
|
const remaining = response.headers.get('X-RateLimit-Remaining');
|
|
if (remaining < 10) {
|
|
await delay(1000); // Slow down
|
|
}
|
|
```
|
|
</Accordion>
|
|
|
|
<Accordion title="Use batch endpoints">
|
|
Reduce total requests by using endpoints that accept multiple IDs:
|
|
|
|
```bash
|
|
# Good: 1 request
|
|
GET /albums?ids=id1,id2,id3,id4,id5
|
|
|
|
# Bad: 5 requests
|
|
GET /albums/id1
|
|
GET /albums/id2
|
|
GET /albums/id3
|
|
GET /albums/id4
|
|
GET /albums/id5
|
|
```
|
|
</Accordion>
|
|
|
|
<Accordion title="Implement caching">
|
|
Cache responses for data that doesn't change frequently:
|
|
|
|
- Album metadata
|
|
- Artist information
|
|
- Track details
|
|
- Genre lists
|
|
|
|
Don't cache:
|
|
- User's current playback
|
|
- Queue information
|
|
- Recently played tracks
|
|
</Accordion>
|
|
|
|
<Accordion title="Use webhooks when available">
|
|
Instead of polling endpoints repeatedly, use webhooks or WebSockets where available.
|
|
</Accordion>
|
|
|
|
<Accordion title="Implement request queuing">
|
|
Queue requests and process them at a controlled rate:
|
|
|
|
```javascript
|
|
class RateLimiter {
|
|
constructor(requestsPerSecond) {
|
|
this.queue = [];
|
|
this.interval = 1000 / requestsPerSecond;
|
|
this.processing = false;
|
|
}
|
|
|
|
async enqueue(fn) {
|
|
return new Promise((resolve, reject) => {
|
|
this.queue.push({ fn, resolve, reject });
|
|
this.process();
|
|
});
|
|
}
|
|
|
|
async process() {
|
|
if (this.processing || this.queue.length === 0) return;
|
|
|
|
this.processing = true;
|
|
const { fn, resolve, reject } = this.queue.shift();
|
|
|
|
try {
|
|
const result = await fn();
|
|
resolve(result);
|
|
} catch (error) {
|
|
reject(error);
|
|
}
|
|
|
|
setTimeout(() => {
|
|
this.processing = false;
|
|
this.process();
|
|
}, this.interval);
|
|
}
|
|
}
|
|
```
|
|
</Accordion>
|
|
</AccordionGroup>
|
|
|
|
## Quota modes
|
|
|
|
Your app's quota mode affects rate limits:
|
|
|
|
### Development mode
|
|
|
|
- Default for new apps
|
|
- Limited API quota
|
|
- Suitable for testing with up to 25 users
|
|
- Lower rate limits
|
|
|
|
### Extended quota mode
|
|
|
|
- Request through Developer Dashboard
|
|
- Higher rate limits
|
|
- Required for production apps
|
|
- Requires app review
|
|
|
|
Learn more about [quota modes](/concepts/quota-modes).
|
|
|
|
## Monitoring rate limits
|
|
|
|
Track your rate limit usage:
|
|
|
|
```javascript
|
|
class RateLimitMonitor {
|
|
constructor() {
|
|
this.stats = {
|
|
totalRequests: 0,
|
|
rateLimitHits: 0,
|
|
currentRemaining: null,
|
|
resetTime: null
|
|
};
|
|
}
|
|
|
|
recordRequest(response) {
|
|
this.stats.totalRequests++;
|
|
|
|
if (response.status === 429) {
|
|
this.stats.rateLimitHits++;
|
|
}
|
|
|
|
this.stats.currentRemaining =
|
|
response.headers.get('X-RateLimit-Remaining');
|
|
this.stats.resetTime =
|
|
response.headers.get('X-RateLimit-Reset');
|
|
}
|
|
|
|
getStats() {
|
|
return {
|
|
...this.stats,
|
|
hitRate: this.stats.rateLimitHits / this.stats.totalRequests
|
|
};
|
|
}
|
|
}
|
|
```
|
|
|
|
## Next steps
|
|
|
|
<CardGroup cols={2}>
|
|
<Card title="API calls" icon="code" href="/concepts/api-calls">
|
|
Best practices for API calls
|
|
</Card>
|
|
<Card title="Quota modes" icon="gauge" href="/concepts/quota-modes">
|
|
Learn about quota modes
|
|
</Card>
|
|
<Card title="Making API calls" icon="book" href="/getting-started/making-api-calls">
|
|
API calls guide
|
|
</Card>
|
|
</CardGroup>
|
|
|