Overview
The Scanova API uses standard HTTP status codes to indicate the success or failure of API requests. This page documents all response codes organized by category, along with their meanings and example responses.
All responses are returned in JSON format (except 204 No Content). Error responses follow a consistent structure with field-level validation details wherever applicable.
Success Responses
Success responses indicate that the request was processed successfully.
200 OK
201 Created
204 No Content
The request was successful. This status code is used for:
- Retrieving resources (GET requests)
- Updating resources (PUT/PATCH requests)
Example Response
{
"id": 123,
"qrid": "Qf94b25d768294148",
"name": "My QR Code",
"category": 1,
"qr_type": "dy",
"created": "2025-01-15T10:30:00Z",
"modified": "2025-01-15T10:30:00Z"
}
Common Use Cases
- GET
/qr/{qrid}/ - Retrieve QR code details
- GET
/qr/ - List QR codes
- PUT/PATCH
/qr/{qrid}/ - Update QR code
- GET
/lead/ - List lead lists
- GET
/analytics/qr/ - Get analytics data
The resource was successfully created. This status code is returned when:
-
Creating a new QR code
-
Creating a new lead list
-
Creating a new user
Example Response
{
"id": 123,
"qrid": "Qf94b25d768294148",
"name": "My New QR Code",
"category": 1,
"qr_type": "dy",
"created": "2025-01-15T10:30:00Z",
"modified": "2025-01-15T10:30:00Z",
"dynamic_url": "https://scanova.io/qr/Qf94b25d768294148"
}
Common Use Cases
-
POST
/qr/ - Create QR code
-
POST
/lead/ - Create lead list
-
POST
/auth/user/ - Get user details
The request was successful and the server has successfully processed the request but is not returning any content. This status code is used for:
-
Deleting resources (DELETE requests)
Response
No response body is returned. The response will have an empty body.
Common Use Cases
-
DELETE
/qr/{qrid}/ - Delete QR code
-
DELETE
/lead/{lead_id}/ - Delete lead list
-
DELETE
/multi-users/{pk}/ - Delete shared user
Example Usage
const response = await fetch(`https://management.scanova.io/qr/${qrid}/`, {
method: 'DELETE',
headers: {
'Authorization': 'YOUR_API_KEY'
}
});
if (response.status === 204) {
console.log('QR code deleted successfully');
// No response body to parse
}
Client Errors
Client errors occur when the request is invalid, missing data, or lacks correct authentication.
400 Bad Request
401 Unauthorized
403 Forbidden
429 Too Many Requests
The request was malformed or contains invalid data. This typically occurs due to:
- Missing required fields
- Invalid field values or formats
- Validation errors
The response follows Django REST Framework (DRF) validation error format:{
"field_name": [
"Error message describing what went wrong with this field."
],
"non_field_errors": [
"General error messages not related to a specific field."
]
}
Example Response
{
"category": [
"This field is required."
],
"info": [
"Invalid JSON format.",
"The 'url' field is required for URL category."
],
"name": [
"This field may not be blank."
]
}
Common Causes
- Missing required fields (
category, info, name, qr_type)
- Invalid JSON in
info or pattern_info fields
- Invalid category ID
- Invalid data structure for the selected category
- Invalid pattern_info format
How to Handle
- Check the response body for field-specific errors
- Validate your request payload against the API documentation
- Ensure all required fields are present
- Verify JSON formatting for
info and pattern_info fields
The request lacks valid authentication credentials. This occurs when:
- No API key is provided
- Invalid or expired API key
- API key format is incorrect
Example Response
{
"detail": "Authentication credentials were not provided."
}
or{
"detail": "Invalid API key."
}
Common Causes
- Missing
Authorization header
- Invalid API key
- Expired API key
- Incorrect API key format
How to Handle
- Verify your API key is correct
- Ensure the
Authorization header is included in the request
- Check that your API key hasn’t been revoked or expired
- Verify you’re using the correct API key format (no “Bearer” prefix needed)
API keys should be passed directly in the Authorization header without any prefix. For example: Authorization: YOUR_API_KEY
The request is valid, but the user doesn’t have permission to perform the requested action. This occurs when:
- User lacks required permissions
- Attempting to access resources from another account
- Account restrictions prevent the action
Example Response
{
"detail": "You do not have permission to perform this action."
}
Common Causes
- Insufficient user permissions
- Attempting to access resources from another account
- Account-level restrictions
- Feature not available for your plan
How to Handle
- Verify your user role has the required permissions
- Check that you’re accessing resources from your own account
- Contact support if you believe you should have access
The rate limit has been exceeded. Too many requests were made in a short period.Example Response
{
"detail": "Request was throttled. Expected available in 60 seconds."
}
How to Handle
- Implement exponential backoff retry logic
- Monitor rate limit headers in responses
- Reduce request frequency
- Consider upgrading your plan for higher limits
Retry Logic Example
async function makeRequestWithRetry(url, options, maxRetries = 3) {
for (let i = 0; i < maxRetries; i++) {
const response = await fetch(url, options);
if (response.status === 429) {
const retryAfter = response.headers.get('Retry-After') || 60;
await new Promise(resolve => setTimeout(resolve, retryAfter * 1000));
continue;
}
return response;
}
throw new Error('Rate limit exceeded after retries');
}
Server Errors
Server errors indicate an issue on Scanova’s end.
An unexpected error occurred on the server. This is a generic server error that indicates something went wrong on our end.Example Response
{
"detail": "An error occurred while processing your request. Please try again later."
}
Common Causes
- Temporary server issues
- Database connectivity problems
- Unexpected server errors
How to Handle
- Retry the request after a short delay
- Implement exponential backoff retry logic
- If the error persists, contact support with:
- The request details
- Timestamp of the error
- Response body (if available)
Retry Logic Example
async function makeRequestWithRetry(url, options, maxRetries = 3) {
for (let i = 0; i < maxRetries; i++) {
try {
const response = await fetch(url, options);
if (response.status === 500 && i < maxRetries - 1) {
// Exponential backoff: wait 1s, 2s, 4s
await new Promise(resolve => setTimeout(resolve, 1000 * Math.pow(2, i)));
continue;
}
return response;
} catch (error) {
if (i === maxRetries - 1) throw error;
await new Promise(resolve => setTimeout(resolve, 1000 * Math.pow(2, i)));
}
}
}
If you encounter persistent 500 errors, please contact our support team with details about the request that failed.
Error Response Best Practices
Always Check Status Codes
Always check the HTTP status code before processing the response body:
const response = await fetch(url, options);
// Handle success responses
if (response.status === 204) {
// No content for DELETE operations
console.log('Operation successful (no content)');
return;
}
if (!response.ok) {
const error = await response.json();
switch (response.status) {
case 400:
console.error('Validation error:', error);
break;
case 401:
console.error('Authentication failed');
break;
case 403:
console.error('Permission denied');
break;
case 429:
console.error('Rate limit exceeded');
break;
case 500:
console.error('Server error');
break;
}
throw new Error(`API Error: ${response.status}`);
}
// Parse JSON only if there's content (not 204)
const data = await response.json();
Handle Field-Specific Errors
For 400 errors, parse field-specific validation errors:
if (response.status === 400) {
const errors = await response.json();
// Handle field-specific errors
Object.keys(errors).forEach(field => {
if (field === 'non_field_errors') {
console.error('General errors:', errors[field]);
} else {
console.error(`Error in ${field}:`, errors[field]);
}
});
}
Implement Retry Logic
Implement retry logic for transient errors (429, 500):
async function makeRequest(url, options, retries = 3) {
for (let i = 0; i < retries; i++) {
try {
const response = await fetch(url, options);
// Retry on rate limit or server errors
if ((response.status === 429 || response.status === 500) && i < retries - 1) {
const delay = response.status === 429
? parseInt(response.headers.get('Retry-After') || '60') * 1000
: 1000 * Math.pow(2, i); // Exponential backoff for 500
await new Promise(resolve => setTimeout(resolve, delay));
continue;
}
return response;
} catch (error) {
if (i === retries - 1) throw error;
await new Promise(resolve => setTimeout(resolve, 1000 * Math.pow(2, i)));
}
}
}
Summary Table
| Status Code | Category | Meaning | Common Use Cases |
|---|
| 200 | Success | Request successful | GET, PUT, PATCH operations |
| 201 | Success | Resource created | POST operations (QR code, lead list, user creation) |
| 204 | Success | No content (deleted) | DELETE operations (QR code, lead list, user deletion) |
| 400 | Client Error | Validation error | Invalid request data, missing fields |
| 401 | Client Error | Authentication failed | Missing or invalid API key |
| 403 | Client Error | Permission denied | Insufficient permissions |
| 429 | Client Error | Rate limit exceeded | Too many requests |
| 500 | Server Error | Internal server error | Server-side issues |
For detailed information about specific endpoints and their responses, refer to the API Reference documentation.