API Responses
Understanding response codes, formats, and error handling strategies
Success Responses
302 Found (Redirect)
Standard successful response
The API returns a 302 redirect to the actual image URL. This is the normal, successful response you'll receive.
Response:
HTTP/1.1 302 Found Location: https://images.unsplash.com/photo-123... X-Cache: HIT X-Image-Source: unsplash X-RateLimit-Limit: 1000 X-RateLimit-Remaining: 987 X-Response-Time: 45ms
How to use:
HTML:
<img src="/api/image?query=..." />Automatically follows redirect
JavaScript:
response.headers.get('Location')Get image URL directly
Client Errors (4xx)
400 Bad Request
Invalid parameters or missing required fields
{
"error": "Missing required parameter: query",
"code": "MISSING_PARAMETER",
"parameter": "query"
}Common causes:
- Missing
queryparameter - Invalid width or height (must be 100-4000)
- Malformed parameters
Fix: Verify all parameters are correctly formatted and within valid ranges
401 Unauthorized
Invalid or expired API key
{
"error": "Invalid API key",
"code": "INVALID_API_KEY"
}Common causes:
- API key doesn't exist
- API key has been revoked
- Incorrect API key format
Fix: Verify your API key is correct and hasn't been revoked. Get a new key if needed.
429 Too Many Requests
Rate limit exceeded
{
"error": "Rate limit exceeded",
"code": "RATE_LIMIT_EXCEEDED",
"limit": 1000,
"remaining": 0,
"reset": "2025-02-09T12:00:00Z",
"retryAfter": 3600
}Response headers:
X-RateLimit-Limit: 1000 X-RateLimit-Remaining: 0 X-RateLimit-Reset: 2025-02-09T12:00:00Z Retry-After: 3600
Fix: Wait for the time specified in Retry-After header, or upgrade your plan.
Server Errors (5xx)
500 Internal Server Error
Unexpected server error
{
"error": "Internal server error",
"code": "INTERNAL_ERROR"
}Fix: This is our fault. Retry after a few moments. If it persists, contact support with the request details.
503 Service Unavailable
Service temporarily unavailable
{
"error": "Service temporarily unavailable",
"code": "SERVICE_UNAVAILABLE"
}Fix: Retry with exponential backoff. Check our status page for updates.
Error Handling Best Practices
Implement Retry Logic
async function fetchImage(query, options = {}) {
const maxRetries = 3;
for (let attempt = 0; attempt < maxRetries; attempt++) {
try {
const response = await fetch(`/api/image?query=${query}`, options);
// Success
if (response.status === 302) {
return response.headers.get('Location');
}
// Rate limit - respect Retry-After
if (response.status === 429) {
const retryAfter = response.headers.get('Retry-After');
const delay = retryAfter ? parseInt(retryAfter) * 1000 : Math.pow(2, attempt) * 1000;
await new Promise(resolve => setTimeout(resolve, delay));
continue;
}
// Client error - don't retry
if (response.status >= 400 && response.status < 500) {
const error = await response.json();
throw new Error(error.error);
}
// Server error - retry with backoff
if (response.status >= 500) {
await new Promise(resolve => setTimeout(resolve, Math.pow(2, attempt) * 1000));
continue;
}
} catch (error) {
if (attempt === maxRetries - 1) throw error;
}
}
throw new Error('Max retries exceeded');
}Handle Errors Gracefully
try {
const imageUrl = await fetchImage('mountains');
setImageSrc(imageUrl);
} catch (error) {
// Show fallback image
setImageSrc('/fallback-image.jpg');
// Log error for monitoring
console.error('Image fetch failed:', error);
// Show user-friendly message
showToast('Could not load image. Please try again.');
}Monitor Error Rates
Track error responses to identify issues early:
- High 4xx rates → Check your implementation
- High 429 rates → Consider upgrading plan
- High 5xx rates → Contact support
Error Code Reference
| Code | HTTP Status | Description | Retry? |
|---|---|---|---|
MISSING_PARAMETER | 400 | Required parameter missing | ❌ No |
INVALID_PARAMETER | 400 | Parameter value invalid | ❌ No |
INVALID_API_KEY | 401 | API key invalid or revoked | ❌ No |
RATE_LIMIT_EXCEEDED | 429 | Too many requests | ✅ Yes (after delay) |
INTERNAL_ERROR | 500 | Server error | ✅ Yes (with backoff) |
SERVICE_UNAVAILABLE | 503 | Service down or overloaded | ✅ Yes (with backoff) |
On This Page