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:

AttributeTypeDescription
400bad_requestThe request was malformed or missing required parameters.
401unauthorizedInvalid or missing API key.
403forbiddenYou don't have permission to access this resource.
404not_foundThe requested resource was not found.
409conflictThe request conflicts with the current state (e.g., duplicate entry).
422validation_errorThe request was well-formed but contains invalid data.
429rate_limit_exceededToo many requests. Please retry after some time.
500internal_errorAn unexpected error occurred on our end.
503service_unavailableThe service is temporarily unavailable. Please retry later.

Error Types

Use the error.type field to programmatically handle different error scenarios:

AttributeTypeDescription
bad_requeststringRequest syntax error or missing required field
unauthorizedstringMissing or invalid API key
forbiddenstringValid API key but insufficient permissions
not_foundstringResource does not exist or belongs to another user
conflictstringResource already exists or state conflict
validation_errorstringField validation failed
rate_limit_exceededstringToo many requests in a time window
internal_errorstringServer-side error
service_unavailablestringService 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.