The SpecStory Cloud API uses conventional HTTP response codes to indicate the success or failure of an API request. Error responses include detailed information to help you understand and resolve issues.

HTTP Status Codes

Success Codes

CodeStatusDescription
200OKRequest succeeded
304Not ModifiedResource hasn’t changed (ETag match)

Client Error Codes

CodeStatusDescription
400Bad RequestInvalid request format or parameters
401UnauthorizedMissing or invalid authentication
403ForbiddenInsufficient permissions
404Not FoundResource doesn’t exist
429Too Many RequestsRate limit exceeded

Server Error Codes

CodeStatusDescription
500Internal Server ErrorUnexpected server error
502Bad GatewayTemporary server issue
503Service UnavailableServer temporarily unavailable

Error Response Format

All error responses follow a consistent JSON structure:
{
  "success": false,
  "error": "Descriptive error message"
}

Example Error Responses

{
  "success": false,
  "error": "Invalid session token"
}

Authentication Errors

401 Unauthorized

Causes:
  • Missing Authorization header
  • Invalid or expired API key
  • Malformed Bearer token
Solutions:
  • Verify your API key is correct
  • Check the Authorization header format: Bearer YOUR_API_KEY
  • Generate a new API key if the current one is expired
curl -H "Authorization: Bearer sk_live_abc123..." \
  https://cloud.specstory.com/api/v1/projects

403 Forbidden

Causes:
  • Attempting to access another user’s resources
  • API key lacks required permissions
  • Resource access restrictions
Solutions:
  • Verify you’re accessing your own projects/sessions
  • Check API key permissions in the dashboard
  • Ensure the resource ID is correct

Resource Errors

404 Not Found

Common scenarios:

Rate Limiting

429 Too Many Requests

The API implements rate limiting to ensure service quality:
  • REST API: 1000 requests per hour
  • GraphQL API: 500 queries per hour
Rate limit headers:
X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 999
X-RateLimit-Reset: 1640995200
Handling rate limits:
async function makeRequest(url, options) {
  const response = await fetch(url, options);
  
  if (response.status === 429) {
    const resetTime = response.headers.get('X-RateLimit-Reset');
    const waitTime = (resetTime * 1000) - Date.now();
    
    console.log(`Rate limited. Waiting ${waitTime}ms`);
    await new Promise(resolve => setTimeout(resolve, waitTime));
    
    // Retry the request
    return makeRequest(url, options);
  }
  
  return response;
}

GraphQL Errors

GraphQL errors are returned in the errors array alongside any partial data:
{
  "data": {
    "project": null
  },
  "errors": [
    {
      "message": "Project not found",
      "locations": [{"line": 2, "column": 3}],
      "path": ["project"],
      "extensions": {
        "code": "NOT_FOUND",
        "projectId": "invalid-id"
      }
    }
  ]
}

Common GraphQL Error Codes

CodeDescriptionSolution
UNAUTHENTICATEDMissing or invalid authenticationCheck Authorization header
FORBIDDENInsufficient permissionsVerify resource access
NOT_FOUNDResource doesn’t existCheck resource ID
VALIDATION_ERRORInvalid query or variablesReview query syntax
RATE_LIMITEDToo many requestsImplement backoff strategy

Validation Errors

400 Bad Request

Request validation failures:

Error Handling Best Practices

Implement Retry Logic

async function apiRequest(url, options, maxRetries = 3) {
  for (let attempt = 1; attempt <= maxRetries; attempt++) {
    try {
      const response = await fetch(url, options);
      
      // Success
      if (response.ok) {
        return await response.json();
      }
      
      // Client errors (4xx) - don't retry
      if (response.status >= 400 && response.status < 500) {
        const error = await response.json();
        throw new Error(error.error);
      }
      
      // Server errors (5xx) - retry with backoff
      if (attempt === maxRetries) {
        throw new Error(`Request failed after ${maxRetries} attempts`);
      }
      
      // Exponential backoff
      const delay = Math.pow(2, attempt) * 1000;
      await new Promise(resolve => setTimeout(resolve, delay));
      
    } catch (error) {
      if (attempt === maxRetries) {
        throw error;
      }
    }
  }
}

Log Errors for Debugging

function handleApiError(error, context) {
  console.error('API Error:', {
    message: error.message,
    context: context,
    timestamp: new Date().toISOString(),
    stack: error.stack
  });
  
  // Report to error tracking service
  // errorTracker.captureException(error, { context });
}

Graceful Degradation

async function getProjectSessions(projectId) {
  try {
    const response = await fetch(`/api/v1/projects/${projectId}/sessions`);
    
    if (!response.ok) {
      throw new Error(`HTTP ${response.status}`);
    }
    
    return await response.json();
    
  } catch (error) {
    console.warn('Failed to load sessions:', error.message);
    
    // Return empty state instead of crashing
    return {
      success: true,
      data: {
        sessions: [],
        total: 0,
        projectId: projectId
      }
    };
  }
}

Troubleshooting Checklist

When encountering API errors:
  1. Check Authentication
    • Verify API key is valid and not expired
    • Ensure proper Authorization header format
    • Test with a simple request like GET /api/v1/projects
  2. Validate Request Format
    • Check JSON syntax and structure
    • Verify required fields are included
    • Ensure parameter values are within allowed ranges
  3. Review Resource Access
    • Confirm resource IDs exist and are accessible
    • Check if you have permissions for the operation
    • Verify project/session relationships
  4. Monitor Rate Limits
    • Check rate limit headers in responses
    • Implement appropriate backoff strategies
    • Consider caching frequently accessed data
  5. Test with GraphQL Playground
    • Use the interactive playground to test queries
    • Validate GraphQL syntax and variables
    • Explore schema documentation for available fields

Getting Help

If you’re still experiencing issues: Include the following information when reporting issues:
  • Request URL and method
  • Request headers and body
  • Response status code and body
  • Timestamp of the request
  • Your API key ID (not the full key)