400 - Bad Request#
Your request is malformed or contains invalid data.
Common causes:
- Missing required fields in request body
- Invalid JSON syntax
- Wrong data types (string instead of integer)
- Sending body with GET request
- Invalid query parameters
{
"error": "Bad Request",
"message": "The issue_id field is required.",
"status": 400
}
- Validate JSON syntax with a linter
- Check API docs for required fields
- Ensure data types match (numbers as numbers, not strings)
- Send request body with GET requests
- Guess at required field names
401 - Unauthorized#
You are not authenticated, or your token is invalid/expired.
Common causes:
- Missing
Authorizationheader - Invalid or expired token
- Token was revoked
- Typo in Bearer token
{
"error": "Unauthorized",
"message": "Unauthenticated.",
"status": 401
}
How to fix:
// Good: Proper authentication
fetch('https://versedb.com/api/user/collection', {
headers: {
'Authorization': 'Bearer YOUR_TOKEN_HERE'
}
})
- Verify token exists and is copied correctly
- Check for extra spaces or characters in token
- Ensure using
Bearerprefix (notTokenorBasic) - Generate new token at: versedb.com/user/api-tokens
- Test token with
GET /api/userfirst
402 - Payment Required#
You're trying to access a PRO-only feature without a PRO subscription.
Common causes:
- Accessing relationship endpoints (
/api/series/{id}/issues) - Accessing market data endpoints
- PRO-only features with free account
{
"error": "Payment Required",
"message": "This endpoint requires a PRO subscription.",
"status": 402
}
Upgrade to PRO at versedb.com/subscription, or use alternative endpoints available to free users.
403 - Forbidden#
You are authenticated but lack permission to perform this action.
Common causes:
- Token lacks required scope/permission
- Attempting to access another user's private data
- Attempting admin operations without admin role
- Resource privacy settings prevent access
{
"error": "Forbidden",
"message": "This action is unauthorized.",
"status": 403
}
Token abilities:
read:public- Read public comic dataread:user- Read your personal datawrite:lists- Manage collections, wishlists, pull listswrite:reviews- Write reviewswrite:favorites- Manage favorites
404 - Not Found#
The requested resource doesn't exist.
Common causes:
- Incorrect or non-existent ID
- Typo in endpoint path
- Using slug instead of numeric ID
- Resource was deleted
{
"error": "Not Found",
"message": "No query results for model [Series] 99999",
"status": 404
}
The API uses numeric IDs, not slugs:
- Good:
GET /api/series/123 - Bad:
GET /api/series/amazing-spider-man-2018
405 - Method Not Allowed#
You're using the wrong HTTP method for this endpoint.
HTTP method reference:
- GET - Read/retrieve data
- POST - Create new resources
- PUT/PATCH - Update existing resources
- DELETE - Remove resources
{
"error": "Method Not Allowed",
"message": "The GET method is not supported for this route.",
"status": 405
}
422 - Unprocessable Entity#
Request is well-formed but contains semantic errors or validation failures.
Common causes:
- Validation rules failed
- Invalid data values
- Foreign key constraints violated
- Business logic rules not met
{
"error": "Unprocessable Entity",
"message": "The given data was invalid.",
"errors": {
"issue_id": ["The selected issue id is invalid."],
"condition": ["The condition must be one of: M, NM, VF, F, VG, G, FR, PR"]
},
"status": 422
}
Read the errors object for specific field issues. Validate data before sending and check allowed values for enum fields.
429 - Too Many Requests#
You've exceeded your rate limit.
{
"error": "Too Many Requests",
"message": "API rate limit exceeded. Please try again later.",
"retry_after": 3600,
"status": 429
}
Response headers:
HTTP/1.1 429 Too Many Requests
X-RateLimit-Limit: 300
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1712869200
Retry-After: 3600
Don't keep retrying immediately. Check the Retry-After header and wait before making more requests.
How to handle:
if (response.status === 429) {
const retryAfter = parseInt(response.headers.get('Retry-After') || '60');
console.log(`Rate limited. Waiting ${retryAfter}s...`);
await new Promise(resolve => setTimeout(resolve, retryAfter * 1000));
}
500 - Internal Server Error#
Something went wrong on the VerseDB server.
{
"error": "Internal Server Error",
"message": "An unexpected error occurred.",
"status": 500
}
What to do:
- Retry with exponential backoff (wait 1s, 2s, 4s between retries)
- If error persists, check VerseDB status page
- Report issue to support with request details and timestamp
500 errors are usually temporary. If consistent, contact support.
503 - Service Unavailable#
The server is temporarily unavailable (maintenance, overload, etc.)
What to do:
- Wait a few minutes and retry
- Check for scheduled maintenance announcements
- Implement graceful degradation in your app
Quick Reference#
| Code | Error | Common Fix |
|---|---|---|
| 400 | Bad Request | Check JSON syntax and required fields |
| 401 | Unauthorized | Add/update Bearer token |
| 402 | Payment Required | Upgrade to PRO subscription |
| 403 | Forbidden | Check token permissions/abilities |
| 404 | Not Found | Verify resource ID exists |
| 405 | Method Not Allowed | Use correct HTTP method |
| 422 | Unprocessable Entity | Fix validation errors |
| 429 | Too Many Requests | Wait and retry, respect rate limits |
| 500 | Server Error | Retry with exponential backoff |
| 503 | Service Unavailable | Wait and retry later |
Debugging Tips#
Log Full Error Response#
fetch(url, {
headers: { 'Authorization': 'Bearer TOKEN' }
})
.then(response => {
if (!response.ok) {
return response.json().then(error => {
console.error('API Error:', {
status: response.status,
error: error,
url: url
});
throw new Error(error.message || 'API request failed');
});
}
return response.json();
});
Test with cURL#
curl -v -H "Authorization: Bearer TOKEN" \
https://versedb.com/api/user/collection