Error Codes Reference
Comprehensive guide to all OilPriceAPI error codes, their meanings, and how to handle them.
Error Response Format
All API errors follow this consistent structure:
{
"status": "error",
"error": {
"code": "RATE_LIMIT_EXCEEDED",
"message": "Rate limit exceeded. Please retry after 60 seconds.",
"details": {
"limit": 100,
"remaining": 0,
"reset_at": "2025-01-23T15:30:00Z",
"reset_after": 60
}
},
"meta": {
"request_id": "req_abc123def456",
"timestamp": "2025-01-23T15:29:00Z"
}
}
HTTP Status Codes
Status | Meaning | Common Causes |
---|---|---|
200 | Success | Request processed successfully |
400 | Bad Request | Invalid parameters or malformed request |
401 | Unauthorized | Missing or invalid API key |
403 | Forbidden | Valid key but insufficient permissions |
404 | Not Found | Endpoint or resource doesn't exist |
429 | Too Many Requests | Rate limit exceeded |
500 | Internal Server Error | Server-side issue |
502 | Bad Gateway | Upstream service unavailable |
503 | Service Unavailable | Temporary maintenance or overload |
Error Codes by Category
Authentication Errors (401)
MISSING_API_KEY
Message: "API key is required. Include it in the Authorization header."
{
"code": "MISSING_API_KEY",
"message": "API key is required. Include it in the Authorization header."
}
How to fix:
curl "https://api.oilpriceapi.com/v1/prices/latest" \
-H "Authorization: Token YOUR_API_KEY" # Add this header
INVALID_API_KEY
Message: "The provided API key is invalid or has been revoked."
{
"code": "INVALID_API_KEY",
"message": "The provided API key is invalid or has been revoked."
}
How to fix:
- Verify key in your dashboard
- Check for typos or extra spaces
- Ensure key hasn't been regenerated
- Use correct prefix (
opa_live_
oropa_test_
)
EXPIRED_API_KEY
Message: "This API key has expired. Please generate a new one."
{
"code": "EXPIRED_API_KEY",
"message": "This API key has expired. Please generate a new one."
}
How to fix:
- Log into dashboard
- Generate new API key
- Update your application configuration
Authorization Errors (403)
INSUFFICIENT_PLAN
Message: "Your current plan doesn't include access to this endpoint."
{
"code": "INSUFFICIENT_PLAN",
"message": "Your current plan doesn't include access to this endpoint.",
"details": {
"current_plan": "hobby",
"required_plan": "professional",
"upgrade_url": "https://oilpriceapi.com/pricing"
}
}
How to fix:
- Check endpoint requirements in documentation
- Upgrade your plan if needed
- Use alternative endpoints available in your tier
QUOTA_EXCEEDED
Message: "Monthly request quota exceeded."
{
"code": "QUOTA_EXCEEDED",
"message": "Monthly request quota exceeded.",
"details": {
"quota": 10000,
"used": 10000,
"reset_date": "2025-02-01T00:00:00Z"
}
}
How to fix:
- Wait for monthly reset
- Upgrade to higher tier
- Optimize API usage (caching, batching)
IP_NOT_WHITELISTED
Message: "Request from this IP address is not allowed."
{
"code": "IP_NOT_WHITELISTED",
"message": "Request from this IP address is not allowed.",
"details": {
"your_ip": "192.168.1.1",
"whitelisted_ips": ["10.0.0.1", "10.0.0.2"]
}
}
How to fix:
- Add IP to whitelist in dashboard
- Use API from approved locations
- Consider VPN if working remotely
Validation Errors (400)
INVALID_COMMODITY
Message: "Invalid commodity code provided."
{
"code": "INVALID_COMMODITY",
"message": "Invalid commodity code provided.",
"details": {
"provided": "INVALID_CODE",
"valid_codes": ["WTI_USD", "BRENT_CRUDE_USD", "NATURAL_GAS_USD"],
"see_all": "https://api.oilpriceapi.com/v1/commodities"
}
}
How to fix:
# Use valid commodity codes
valid_codes = ['WTI_USD', 'BRENT_CRUDE_USD', 'NATURAL_GAS_USD']
response = requests.get(
f'https://api.oilpriceapi.com/v1/prices/latest?by_code={valid_codes[0]}'
)
INVALID_DATE_RANGE
Message: "Invalid date range. Start date must be before end date."
{
"code": "INVALID_DATE_RANGE",
"message": "Invalid date range. Start date must be before end date.",
"details": {
"start": "2025-02-01",
"end": "2025-01-01",
"max_range_days": 365
}
}
How to fix:
// Ensure proper date ordering
const start = '2025-01-01';
const end = '2025-02-01';
const url = `https://api.oilpriceapi.com/v1/prices?start=${start}&end=${end}`;
INVALID_PARAMETER
Message: "Invalid parameter value."
{
"code": "INVALID_PARAMETER",
"message": "Invalid parameter value.",
"details": {
"parameter": "interval",
"provided": "2h",
"valid_values": ["raw", "1h", "hourly", "1d", "daily", "1w", "weekly", "1m", "monthly"]
}
}
How to fix:
- Use only documented parameter values
- Check spelling and case sensitivity
- Remove unsupported parameters
MISSING_REQUIRED_PARAMETER
Message: "Required parameter is missing."
{
"code": "MISSING_REQUIRED_PARAMETER",
"message": "Required parameter is missing.",
"details": {
"parameter": "by_code",
"description": "Commodity code is required for this endpoint"
}
}
How to fix:
# Add required parameter
curl "https://api.oilpriceapi.com/v1/prices/latest?by_code=WTI_USD"
# ^^^^^^^^^^^^^^^^ Add this
Rate Limiting Errors (429)
RATE_LIMIT_EXCEEDED
Message: "Rate limit exceeded."
{
"code": "RATE_LIMIT_EXCEEDED",
"message": "Rate limit exceeded. Please retry after 60 seconds.",
"details": {
"limit": 60,
"window": "1 minute",
"remaining": 0,
"reset_at": "2025-01-23T15:30:00Z",
"reset_after": 45
}
}
How to fix:
import time
import requests
def make_request_with_retry(url, headers, max_retries=3):
for attempt in range(max_retries):
response = requests.get(url, headers=headers)
if response.status_code == 429:
reset_after = int(response.headers.get('X-RateLimit-Reset-After', 60))
print(f"Rate limited. Waiting {reset_after} seconds...")
time.sleep(reset_after)
continue
return response
raise Exception("Max retries exceeded")
Resource Errors (404)
ENDPOINT_NOT_FOUND
Message: "The requested endpoint does not exist."
{
"code": "ENDPOINT_NOT_FOUND",
"message": "The requested endpoint does not exist.",
"details": {
"requested": "/v1/prices/invalid",
"available": ["/v1/prices/latest", "/v1/prices/past_day", "/v1/prices/past_week"]
}
}
How to fix:
- Check documentation for correct endpoint paths
- Verify API version (v1)
- Remove trailing slashes
COMMODITY_NOT_FOUND
Message: "The requested commodity does not exist."
{
"code": "COMMODITY_NOT_FOUND",
"message": "The requested commodity does not exist.",
"details": {
"requested": "UNKNOWN_USD",
"suggestion": "Did you mean WTI_USD?"
}
}
Server Errors (500+)
INTERNAL_ERROR
Message: "An internal server error occurred."
{
"code": "INTERNAL_ERROR",
"message": "An internal server error occurred. Please try again later.",
"details": {
"request_id": "req_abc123",
"support_email": "[email protected]"
}
}
How to fix:
- Retry with exponential backoff
- Report persistent issues with request_id
- Check status page for known issues
DATA_SOURCE_ERROR
Message: "Unable to fetch data from upstream source."
{
"code": "DATA_SOURCE_ERROR",
"message": "Unable to fetch data from upstream source.",
"details": {
"source": "primary_feed",
"fallback_available": true,
"retry_after": 30
}
}
How to fix:
- Retry after suggested time
- System will use fallback sources automatically
- Monitor status page for updates
SERVICE_UNAVAILABLE
Message: "Service temporarily unavailable."
{
"code": "SERVICE_UNAVAILABLE",
"message": "Service temporarily unavailable for maintenance.",
"details": {
"maintenance_window": "2025-01-23T02:00:00Z to 2025-01-23T02:30:00Z",
"status_page": "https://status.oilpriceapi.com"
}
}
Error Handling Best Practices
1. Implement Retry Logic
async function apiRequest(url, options, maxRetries = 3) {
let lastError;
for (let i = 0; i < maxRetries; i++) {
try {
const response = await fetch(url, options);
if (response.ok) {
return await response.json();
}
const error = await response.json();
// Don't retry client errors
if (response.status >= 400 && response.status < 500) {
if (response.status !== 429) { // Except rate limits
throw new Error(error.error.message);
}
}
// Wait before retry
const retryAfter = response.headers.get('Retry-After') || (i + 1) * 1000;
await new Promise(resolve => setTimeout(resolve, retryAfter));
lastError = error;
} catch (err) {
lastError = err;
// Network error - always retry
await new Promise(resolve => setTimeout(resolve, (i + 1) * 1000));
}
}
throw lastError;
}
2. Parse Error Details
def handle_api_error(response):
"""Extract and handle API errors properly"""
if response.status_code == 200:
return response.json()
try:
error_data = response.json()
error_code = error_data.get('error', {}).get('code')
error_message = error_data.get('error', {}).get('message')
error_details = error_data.get('error', {}).get('details', {})
if error_code == 'RATE_LIMIT_EXCEEDED':
# Wait and retry
reset_after = error_details.get('reset_after', 60)
time.sleep(reset_after)
return None # Signal retry
elif error_code == 'INSUFFICIENT_PLAN':
# Log and notify about plan upgrade
upgrade_url = error_details.get('upgrade_url')
logging.error(f"Plan upgrade needed: {upgrade_url}")
elif error_code == 'INVALID_COMMODITY':
# Use fallback commodity
valid_codes = error_details.get('valid_codes', [])
if valid_codes:
return use_fallback_commodity(valid_codes[0])
except json.JSONDecodeError:
# Non-JSON error response
logging.error(f"API error {response.status_code}: {response.text}")
raise APIError(response.status_code, error_code, error_message)
3. Log Errors for Monitoring
function logApiError(error, context) {
const errorLog = {
timestamp: new Date().toISOString(),
request_id: error.meta?.request_id,
error_code: error.error?.code,
message: error.error?.message,
status: error.status,
context: context,
details: error.error?.details
};
// Send to monitoring service
console.error('API Error:', errorLog);
// Send to analytics
if (window.analytics) {
window.analytics.track('API Error', errorLog);
}
}
4. Graceful Degradation
def get_price_with_fallback(commodity_code):
"""Get price with fallback strategies"""
# Try primary API
try:
return fetch_from_api(commodity_code)
except APIError as e:
if e.code == 'QUOTA_EXCEEDED':
# Use cached data if quota exceeded
return get_cached_price(commodity_code)
elif e.code == 'COMMODITY_NOT_FOUND':
# Try alternative commodity codes
alternatives = {
'WTI': 'WTI_USD',
'BRENT': 'BRENT_CRUDE_USD',
'GAS': 'NATURAL_GAS_USD'
}
if commodity_code in alternatives:
return fetch_from_api(alternatives[commodity_code])
elif e.code in ['INTERNAL_ERROR', 'SERVICE_UNAVAILABLE']:
# Use last known good value
return get_last_known_price(commodity_code)
# Re-raise if no fallback available
raise
Testing Error Handling
# Test your error handling
def test_error_handling():
test_cases = [
# Missing API key
{'headers': {}, 'expected_code': 'MISSING_API_KEY'},
# Invalid API key
{'headers': {'Authorization': 'Token invalid'},
'expected_code': 'INVALID_API_KEY'},
# Invalid commodity
{'params': {'by_code': 'INVALID'},
'expected_code': 'INVALID_COMMODITY'},
# Invalid date range
{'params': {'start': '2025-02-01', 'end': '2025-01-01'},
'expected_code': 'INVALID_DATE_RANGE'}
]
for test in test_cases:
response = make_test_request(**test)
assert response.get('error', {}).get('code') == test['expected_code']
Quick Reference Table
Error Code | HTTP Status | Retry? | Action |
---|---|---|---|
MISSING_API_KEY | 401 | No | Add API key |
INVALID_API_KEY | 401 | No | Check/regenerate key |
INSUFFICIENT_PLAN | 403 | No | Upgrade plan |
QUOTA_EXCEEDED | 403 | After reset | Wait or upgrade |
RATE_LIMIT_EXCEEDED | 429 | Yes | Wait and retry |
INVALID_COMMODITY | 400 | No | Fix commodity code |
INVALID_PARAMETER | 400 | No | Fix parameter |
INTERNAL_ERROR | 500 | Yes | Retry with backoff |
SERVICE_UNAVAILABLE | 503 | Yes | Wait and retry |
Support
For persistent errors or issues not covered here:
- Email: [email protected]
- Include: Error code, request_id, timestamp
- Response time: 3 business days