Errors
The Odyssey API uses standard HTTP status codes to indicate the success or failure of requests. This guide covers the error codes you might encounter and how to handle them.
Status codes
- Name
200 OK- Description
The request was successful.
- Name
201 Created- Description
A new resource was successfully created.
- Name
204 No Content- Description
The request was successful and there is no content to return (common for the ingest endpoint).
- Name
400 Bad Request- Description
The request was malformed or contains invalid data.
- Name
401 Unauthorized- Description
Authentication failed or API key is invalid.
- Name
403 Forbidden- Description
The API key doesn't have permission to access this resource or the request origin is not allowed.
- Name
404 Not Found- Description
The requested resource doesn't exist.
- Name
409 Conflict- Description
The request conflicts with existing data (e.g., duplicate slug or step key).
- Name
429 Too Many Requests- Description
Rate limit exceeded. Wait before making more requests.
- Name
500 Internal Server Error- Description
An unexpected error occurred on the server.
Error response format
Error responses include a JSON object with an error field describing the problem:
Error response
{
"error": "Journey with slug \"my-journey\" not found"
}
Authentication errors
401 Unauthorized
Your API key is missing, invalid, or expired:
{
"error": "Invalid or expired API key"
}
How to fix:
- Verify your API key is correct
- Check that the key hasn't expired
- Ensure you're including the key in the
Authorizationheader:Bearer {your_key}
403 Forbidden
Your API key doesn't have the required scopes:
{
"error": "API key does not have required scope: journeys:write"
}
How to fix:
- Check which scopes your key has in the dashboard
- Create a new key with the required scopes
- Contact your organization admin if you need additional permissions
Validation errors
400 Bad Request
The request data is invalid or malformed:
{
"error": "Invalid journey data: slug must contain only lowercase letters, numbers, and hyphens"
}
Common causes:
- Missing required fields
- Invalid data types (string instead of integer, etc.)
- Invalid format (slug with uppercase letters, invalid timestamp, etc.)
- Malformed JSON
How to fix:
- Review the error message for specific details
- Check the API documentation for required fields and formats
- Validate your JSON before sending
Resource errors
404 Not Found
The requested resource doesn't exist:
{
"error": "Journey with slug \"nonexistent-journey\" not found"
}
How to fix:
- Verify the resource identifier (slug, ID, etc.) is correct
- Check that the resource belongs to your organization
- Ensure the resource hasn't been deleted
409 Conflict
The request conflicts with existing data:
{
"error": "Journey with slug \"my-journey\" already exists in this organization"
}
Common causes:
- Duplicate slug when creating a journey
- Duplicate step key when adding a step
- Duplicate index when reordering steps
How to fix:
- Use a different, unique identifier
- Check existing resources before creating new ones
- For updates, use PUT instead of POST
Rate limiting errors
429 Too Many Requests
You've exceeded your rate limit:
{
"error": "Rate limit exceeded for organization"
}
How to fix:
- Wait before making more requests (check
Retry-Afterheader if present) - Implement exponential backoff in your client
- Contact support to request a rate limit increase
- Optimize your code to make fewer requests (batch operations, cache results, etc.)
Server errors
500 Internal Server Error
An unexpected error occurred on the server:
{
"error": "Internal server error"
}
How to fix:
- Retry the request after a short delay
- If the error persists, contact support with details about your request
- Check the status page for known issues
Handling errors in your code
JavaScript/TypeScript
async function createJourney(data) {
try {
const response = await fetch('https://odysseylabs.ai/api/journeys/create', {
method: 'POST',
headers: {
'Authorization': `Bearer ${apiKey}`,
'Content-Type': 'application/json'
},
body: JSON.stringify(data)
})
if (!response.ok) {
const error = await response.json()
if (response.status === 401) {
console.error('Invalid API key')
} else if (response.status === 409) {
console.error('Journey already exists:', error.error)
} else if (response.status === 429) {
console.error('Rate limited, waiting...')
await new Promise(resolve => setTimeout(resolve, 60000))
return createJourney(data) // Retry
} else {
console.error('API error:', error.error)
}
throw new Error(error.error)
}
return await response.json()
} catch (error) {
console.error('Request failed:', error)
throw error
}
}
Python
import requests
import time
def create_journey(api_key, data):
headers = {
'Authorization': f'Bearer {api_key}',
'Content-Type': 'application/json'
}
response = requests.post(
'https://odysseylabs.ai/api/journeys/create',
headers=headers,
json=data
)
if response.status_code == 401:
raise Exception('Invalid API key')
elif response.status_code == 409:
raise Exception(f'Journey already exists: {response.json()["error"]}')
elif response.status_code == 429:
print('Rate limited, waiting 60 seconds...')
time.sleep(60)
return create_journey(api_key, data) # Retry
elif not response.ok:
raise Exception(f'API error: {response.json()["error"]}')
return response.json()
Best practices
- Name
Check status codes- Description
Always check HTTP status codes before parsing response bodies.
- Name
Handle all error types- Description
Account for 4xx client errors, 5xx server errors, and network failures.
- Name
Implement retries- Description
Use exponential backoff for rate limit and server errors.
- Name
Log errors- Description
Capture full error context for debugging (request ID, timestamp, payload).
- Name
User-friendly messages- Description
Don't show raw API errors to end users - translate them to actionable messages.
- Name
Monitor error rates- Description
Track error frequency to identify API issues or misuse patterns.
Getting help
If you're experiencing persistent errors or need assistance:
- Check the status page for known issues
- Review your API key scopes in the dashboard
- Contact support with:
- Request timestamp
- API endpoint
- Error message
- Request payload (without sensitive data)