Errors
MyOpcs uses conventional HTTP response codes to indicate API request status. This guide helps you understand and handle errors effectively.
Error Response Format
All error responses follow a consistent JSON structure with an error object:
{}JSON
{
"error": {
"type": "error_type",
"message": "A human-readable error message",
"details": {
"field": "Additional context about the error"
}
}
}HTTP Status Codes
Reference for all HTTP status codes returned by the API:
| Attribute | Type | Description |
|---|---|---|
400 | bad_request | The request was malformed or missing required parameters. |
401 | unauthorized | Invalid or missing API key. |
403 | forbidden | You don't have permission to access this resource. |
404 | not_found | The requested resource was not found. |
409 | conflict | The request conflicts with the current state (e.g., duplicate entry). |
422 | validation_error | The request was well-formed but contains invalid data. |
429 | rate_limit_exceeded | Too many requests. Please retry after some time. |
500 | internal_error | An unexpected error occurred on our end. |
503 | service_unavailable | The service is temporarily unavailable. Please retry later. |
Error Types
Use the error.type field to programmatically handle different error scenarios:
| Attribute | Type | Description |
|---|---|---|
bad_request | string | Request syntax error or missing required field |
unauthorized | string | Missing or invalid API key |
forbidden | string | Valid API key but insufficient permissions |
not_found | string | Resource does not exist or belongs to another user |
conflict | string | Resource already exists or state conflict |
validation_error | string | Field validation failed |
rate_limit_exceeded | string | Too many requests in a time window |
internal_error | string | Server-side error |
service_unavailable | string | Service temporarily down for maintenance |
Common Error Examples
Examples of common error responses you may encounter:
Invalid API Key
401{
"error": {
"type": "unauthorized",
"message": "Invalid API key provided"
}
}Permission Denied
403{
"error": {
"type": "forbidden",
"message": "You don't have access to this product",
"details": {
"resource": "product",
"productId": "prod_abc123"
}
}
}Resource Not Found
404{
"error": {
"type": "not_found",
"message": "Product not found",
"details": {
"resource": "product",
"id": "prod_abc123"
}
}
}Duplicate Resource
409{
"error": {
"type": "conflict",
"message": "Version already exists",
"details": {
"version": "1.2.0",
"productId": "prod_abc123"
}
}
}Validation Error
422{
"error": {
"type": "validation_error",
"message": "Validation failed",
"details": {
"version": "Version must be in semver format (e.g., 1.2.0)",
"content": "Content is required"
}
}
}Rate Limit Exceeded
429{
"error": {
"type": "rate_limit_exceeded",
"message": "Rate limit exceeded. Please retry after 60 seconds.",
"details": {
"retryAfter": 60,
"limit": 100,
"remaining": 0
}
}
}Rate Limits
API requests are rate limited to ensure fair usage:
100
requests per minute per API key
10,000
requests per day per API key
Rate Limit Headers
Every response includes
X-RateLimit-Limit, X-RateLimit-Remaining, and X-RateLimit-Reset headers to help you track usage.Best Practices
Always Check error.type
const response = await fetch(url, options);
const data = await response.json();
if (!response.ok) {
switch (data.error.type) {
case 'unauthorized':
// Refresh API key or prompt user to reconnect
break;
case 'rate_limit_exceeded':
// Wait and retry with exponential backoff
const waitTime = data.error.details.retryAfter * 1000;
await sleep(waitTime);
return retry();
case 'validation_error':
// Show validation errors to user
console.log(data.error.details);
break;
default:
// Handle other errors
console.error(data.error.message);
}
}Implement Exponential Backoff
async function fetchWithRetry(url, options, maxRetries = 3) {
for (let attempt = 0; attempt < maxRetries; attempt++) {
const response = await fetch(url, options);
if (response.ok || response.status < 500) {
return response; // Don't retry client errors
}
if (response.status === 429) {
const data = await response.json();
const waitTime = (data.error.details?.retryAfter || 60) * 1000;
await new Promise(r => setTimeout(r, waitTime));
} else {
// Exponential backoff for server errors
const delay = Math.pow(2, attempt) * 1000 + Math.random() * 1000;
await new Promise(r => setTimeout(r, delay));
}
}
throw new Error('Max retries exceeded');
}Need Help?
If you're experiencing persistent errors, check the response body for detailed error messages. For server errors (5xx), the issue is usually temporary—retry with exponential backoff.