Error Handling
The TakeTheme API uses conventional HTTP response codes to indicate the success or failure of requests. This guide covers error response formats and best practices for handling them.
HTTP Status Codes
| Code Range | Meaning |
|---|---|
2xx | Success — The request completed successfully |
4xx | Client Error — There's a problem with your request |
5xx | Server Error — Something went wrong on our end |
Common Status Codes
| Code | Status | Description |
|---|---|---|
200 | OK | Request succeeded |
201 | Created | Resource created successfully |
204 | No Content | Request succeeded, no content returned |
400 | Bad Request | Invalid request parameters |
401 | Unauthorized | Missing or invalid authentication |
403 | Forbidden | Insufficient permissions |
404 | Not Found | Resource doesn't exist |
409 | Conflict | Resource state conflict |
429 | Too Many Requests | Rate limit exceeded |
500 | Internal Server Error | Server-side error |
503 | Service Unavailable | Temporary outage |
Error Response Format
All errors follow a simple JSON structure with status and message fields:
{
"status": 400,
"message": "\"email\" is required"
}
Error Object Fields
| Field | Type | Description |
|---|---|---|
status | number | HTTP status code |
message | string | Human-readable error description |
Some error responses may include additional fields depending on the error type.
Error Types
Authentication Errors
When API key authentication fails:
{
"status": 401,
"message": "API key is required. Provide it via tt-api-key header or Authorization: Bearer header"
}
Invalid API key format:
{
"status": 401,
"message": "API key must start with tt_ prefix"
}
Revoked or invalid API key:
{
"status": 401,
"message": "API key not found or has been revoked"
}
Expired API key:
{
"status": 401,
"message": "API key has expired"
}
Authorization Errors
Insufficient permissions:
{
"status": 403,
"message": "API key does not have access to PRODUCTS"
}
Missing required action:
{
"status": 403,
"message": "API key cannot perform WRITE on PRODUCTS"
}
IP not whitelisted:
{
"status": 403,
"message": "Your IP address is not authorized to use this API key"
}
Validation Errors
When request validation fails:
{
"status": 400,
"message": "\"email\" must be a valid email"
}
{
"status": 400,
"message": "\"price\" must be greater than or equal to 0"
}
Not Found Errors
When a resource or route doesn't exist:
{
"name": "Resource not found",
"message": "The page you are trying to access does not exist"
}
Rate Limit Errors
When rate limit is exceeded:
{
"message": "Rate limit exceeded",
"code": "RATE_LIMIT_EXCEEDED",
"status": 429
}
Server Errors
When an internal server error occurs:
{
"status": 500,
"message": "INTERNAL_SERVER_ERROR"
}
Duplicate Entry Errors
When attempting to create a resource that already exists:
{
"status": 400,
"message": "slug and storeId combination with my-product and 65abc123def already exists."
}
Handling Errors
JavaScript/TypeScript
interface ApiError {
status: number;
message: string;
code?: string;
name?: string;
}
async function apiRequest<T>(
endpoint: string,
options?: RequestInit
): Promise<T> {
const response = await fetch(`https://api.taketheme.com/api/v1${endpoint}`, {
...options,
headers: {
"tt-api-key": API_KEY,
"Content-Type": "application/json",
...options?.headers,
},
});
const data = await response.json();
if (!response.ok) {
const error = data as ApiError;
switch (response.status) {
case 401:
throw new AuthenticationError(error.message);
case 403:
throw new ForbiddenError(error.message);
case 404:
throw new NotFoundError(error.message || error.name);
case 429:
throw new RateLimitError(error.message);
default:
throw new ApiError(error.message, error.status);
}
}
return data as T;
}
// Usage
try {
const product = await apiRequest("/products/prod_123");
} catch (error) {
if (error instanceof RateLimitError) {
// Wait and retry
await sleep(60000);
// Retry request...
} else if (error instanceof NotFoundError) {
console.log("Product not found");
} else if (error instanceof AuthenticationError) {
console.log("Check your API key");
} else {
console.error("Unexpected error:", error.message);
}
}
Python
import requests
from typing import Optional
class ApiError(Exception):
def __init__(self, message: str, status: int):
super().__init__(message)
self.message = message
self.status = status
class AuthenticationError(ApiError):
pass
class ForbiddenError(ApiError):
pass
class NotFoundError(ApiError):
pass
class RateLimitError(ApiError):
pass
def api_request(endpoint: str, method: str = 'GET', data: Optional[dict] = None) -> dict:
response = requests.request(
method,
f'https://api.taketheme.com/api/v1{endpoint}',
headers={
'tt-api-key': API_KEY,
'Content-Type': 'application/json'
},
json=data
)
result = response.json()
if not response.ok:
message = result.get('message', result.get('name', 'Unknown error'))
status = result.get('status', response.status_code)
if response.status_code == 401:
raise AuthenticationError(message, status)
elif response.status_code == 403:
raise ForbiddenError(message, status)
elif response.status_code == 404:
raise NotFoundError(message, status)
elif response.status_code == 429:
raise RateLimitError(message, status)
else:
raise ApiError(message, status)
return result
# Usage
try:
product = api_request('/products/prod_123')
except RateLimitError as e:
import time
time.sleep(60)
# Retry request...
except NotFoundError as e:
print("Product not found")
except AuthenticationError as e:
print("Check your API key")
except ApiError as e:
print(f"Error: {e.message} (Status: {e.status})")
Error Codes Reference
Authentication & Authorization
| Error Message | Status | Description |
|---|---|---|
API key is required... | 401 | No API key provided |
API key must start with tt_ prefix | 401 | Invalid API key format |
API key not found or has been revoked | 401 | API key doesn't exist or was revoked |
API key has expired | 401 | API key past expiration date |
API key usage limit has been reached | 429 | Usage quota exceeded |
API key does not have access to [RESOURCE] | 403 | Missing resource scope |
API key cannot perform [ACTION] on [RESOURCE] | 403 | Missing action permission |
Your IP address is not authorized... | 403 | IP not in whitelist |
Rate Limiting
| Error Message | Code | Status | Description |
|---|---|---|---|
Rate limit exceeded | RATE_LIMIT_EXCEEDED | 429 | Too many requests |
Validation
Validation error messages are generated by the request schema and describe exactly which field failed and why. Common patterns include:
| Pattern | Description |
|---|---|
"[field]" is required | Required field is missing |
"[field]" must be a valid email | Invalid email format |
"[field]" must be greater than [value] | Value below minimum |
"[field]" must be less than [value] | Value exceeds maximum |
"[field]" must be one of [values] | Invalid enum value |
"[field]" must be a string | Wrong data type |
Resources
| Error Message | Status | Description |
|---|---|---|
The page you are trying to access does not exist | 404 | Route or resource not found |
[field] combination with [values] already exists. | 400 | Duplicate entry |
Best Practices
1. Always Check for Errors
// ✗ Bad: Ignoring potential errors
const { data } = await fetch("/products");
renderProducts(data);
// ✓ Good: Handling errors explicitly
const response = await fetch("/products");
if (!response.ok) {
const error = await response.json();
console.error("Error:", error.message);
return;
}
const { data } = await response.json();
renderProducts(data);
2. Handle Different Status Codes
async function handleApiError(response) {
const error = await response.json();
switch (response.status) {
case 400:
return `Validation error: ${error.message}`;
case 401:
return `Authentication failed: ${error.message}`;
case 403:
return `Permission denied: ${error.message}`;
case 404:
return "Resource not found";
case 429:
return "Rate limit exceeded. Please wait before retrying.";
case 500:
return "Server error. Please try again later.";
default:
return error.message || "An unexpected error occurred";
}
}
3. Display User-Friendly Messages
function getUserMessage(error) {
// Don't expose internal error details to users
if (error.status >= 500) {
return "Something went wrong. Please try again later.";
}
if (error.status === 429) {
return "Too many requests. Please wait a moment.";
}
// For client errors, the message is usually safe to show
return error.message;
}
4. Implement Retry Logic for Transient Errors
async function fetchWithRetry(endpoint, maxRetries = 3) {
for (let attempt = 0; attempt < maxRetries; attempt++) {
try {
const response = await apiRequest(endpoint);
return response;
} catch (error) {
// Only retry on server errors or rate limits
if (error.status !== 500 && error.status !== 503 && error.status !== 429) {
throw error; // Don't retry client errors
}
// Exponential backoff
const delay = Math.pow(2, attempt) * 1000;
await new Promise(resolve => setTimeout(resolve, delay));
}
}
throw new Error("Max retries exceeded");
}