Error Handling

Understand API error responses, status codes, and implement robust error handling with retry logic and best practices

Errors

The Thrive Public API uses conventional HTTP response codes and returns standardized error responses to indicate the success or failure of requests.

HTTP Status Codes

Status CodeDescription
200Success - Request completed successfully
201Created - Resource created successfully (e.g., new application or document)
400Bad Request - Invalid request parameters or malformed request
401Unauthorized - Invalid or missing authentication credentials
403Forbidden - Valid credentials but insufficient permissions
404Not Found - Requested resource does not exist
422Unprocessable Entity - Valid request format but business logic error
429Too Many Requests - Rate limit exceeded
500Internal Server Error - Server error occurred
503Service Unavailable - Service temporarily unavailable
504Gateway Timeout - Upstream service did not respond in time

Error Response Format

All errors follow this consistent structure:

{
  "timestamp": "2024-01-15T10:30:00.000Z",
  "statusCode": 400,
  "result": {
    "data": null,
    "error": {
      "message": "Human-readable error description",
      "code": "MACHINE_READABLE_ERROR_CODE",
      "details": {
        "field": "additional_context"
      }
    }
  }
}

Common Error Codes

Authentication Errors

Invalid Credentials

{
  "statusCode": 401,
  "result": {
    "data": null,
    "error": {
      "message": "Invalid client credentials provided",
      "code": "INVALID_CREDENTIALS"
    }
  }
}

Expired Token

{
  "statusCode": 401,
  "result": {
    "data": null,
    "error": {
      "message": "Access token has expired",
      "code": "TOKEN_EXPIRED",
      "details": {
        "expired_at": "2024-01-15T10:30:00.000Z"
      }
    }
  }
}

Missing Authorization

{
  "statusCode": 401,
  "result": {
    "data": null,
    "error": {
      "message": "Authorization header is required",
      "code": "MISSING_AUTHORIZATION"
    }
  }
}

Validation Errors

Missing Required Fields

{
  "statusCode": 400,
  "result": {
    "data": null,
    "error": {
      "message": "Required fields are missing",
      "code": "VALIDATION_ERROR",
      "details": {
        "missing_fields": ["borrower.email", "loan_amount"]
      }
    }
  }
}

Invalid Field Values

{
  "statusCode": 400,
  "result": {
    "data": null,
    "error": {
      "message": "Invalid field values provided",
      "code": "VALIDATION_ERROR",
      "details": {
        "invalid_fields": {
          "loan_amount": "Must be between 1,000 and 100,000",
          "borrower.email": "Must be a valid email address"
        }
      }
    }
  }
}

Business Logic Errors

Application Not Found

{
  "statusCode": 404,
  "result": {
    "data": null,
    "error": {
      "message": "Loan application not found",
      "code": "APPLICATION_NOT_FOUND",
      "details": {
        "application_uid": "app_123456789"
      }
    }
  }
}

Application Already Exists

{
  "statusCode": 422,
  "result": {
    "data": null,
    "error": {
      "message": "Application already exists for this borrower and project",
      "code": "DUPLICATE_APPLICATION",
      "details": {
        "existing_application_uid": "app_987654321"
      }
    }
  }
}

Insufficient Funds

{
  "statusCode": 422,
  "result": {
    "data": null,
    "error": {
      "message": "Insufficient available balance for draw request",
      "code": "INSUFFICIENT_BALANCE",
      "details": {
        "requested_amount": 15000.00,
        "available_balance": 10000.00
      }
    }
  }
}

File Upload Errors

File Too Large

{
  "statusCode": 400,
  "result": {
    "data": null,
    "error": {
      "message": "File size exceeds maximum allowed limit",
      "code": "FILE_TOO_LARGE",
      "details": {
        "max_file_size": "10MB",
        "received_file_size": "15.2MB"
      }
    }
  }
}

Invalid File Type

{
  "statusCode": 400,
  "result": {
    "data": null,
    "error": {
      "message": "File type not supported",
      "code": "INVALID_FILE_TYPE",
      "details": {
        "allowed_types": ["image/jpeg", "image/png", "application/pdf"],
        "received_type": "application/zip"
      }
    }
  }
}

Rate Limiting Errors

Rate Limit Exceeded

{
  "statusCode": 429,
  "result": {
    "data": null,
    "error": {
      "message": "Rate limit exceeded. Try again later",
      "code": "RATE_LIMIT_EXCEEDED",
      "details": {
        "limit": 1000,
        "window": "1 hour",
        "reset_at": "2024-01-15T11:00:00.000Z"
      }
    }
  }
}

Error Handling Best Practices

1. Always Check Status Code

const response = await fetch('/api/application', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${token}`,
    'Content-Type': 'application/json'
  },
  body: JSON.stringify(applicationData)
});

if (!response.ok) {
  const error = await response.json();
  console.error('API Error:', error.result.error);
  throw new Error(error.result.error.message);
}

const result = await response.json();

2. Handle Specific Error Codes

function handleApiError(error) {
  switch (error.code) {
    case 'TOKEN_EXPIRED':
      // Refresh token and retry request
      return refreshTokenAndRetry();
      
    case 'VALIDATION_ERROR':
      // Show field-specific error messages
      showFieldErrors(error.details.invalid_fields);
      break;
      
    case 'RATE_LIMIT_EXCEEDED':
      // Implement exponential backoff
      const resetTime = new Date(error.details.reset_at);
      return retryAfter(resetTime);
      
    case 'APPLICATION_NOT_FOUND':
      // Redirect to application creation
      redirectToCreateApplication();
      break;
      
    default:
      // Generic error handling
      showGenericError(error.message);
  }
}

3. Implement Retry Logic

async function apiRequestWithRetry(url, options, maxRetries = 3) {
  for (let attempt = 1; attempt <= maxRetries; attempt++) {
    try {
      const response = await fetch(url, options);
      
      if (response.ok) {
        return response;
      }
      
      const error = await response.json();
      
      // Don't retry client errors (4xx) except 429
      if (response.status >= 400 && response.status < 500 && response.status !== 429) {
        throw new Error(error.result.error.message);
      }
      
      // Exponential backoff for retryable errors
      if (attempt < maxRetries) {
        const delay = Math.pow(2, attempt) * 1000; // 2s, 4s, 8s
        await new Promise(resolve => setTimeout(resolve, delay));
      }
      
    } catch (error) {
      if (attempt === maxRetries) {
        throw error;
      }
    }
  }
}

4. Log Errors for Debugging

function logApiError(endpoint, error, requestData) {
  console.error('API Error Details:', {
    endpoint,
    statusCode: error.statusCode,
    errorCode: error.result.error.code,
    message: error.result.error.message,
    details: error.result.error.details,
    requestData,
    timestamp: error.timestamp
  });
}

Error Code Reference

Authentication (AUTH_*)

  • INVALID_CREDENTIALS - Client ID/secret combination is invalid
  • TOKEN_EXPIRED - Access token has expired
  • MISSING_AUTHORIZATION - Authorization header not provided
  • INVALID_TOKEN - Token format is invalid or corrupted

Validation (VALIDATION_*)

  • VALIDATION_ERROR - Request data fails validation rules
  • MISSING_REQUIRED_FIELD - Required field not provided
  • INVALID_FIELD_VALUE - Field value doesn't meet constraints
  • INVALID_JSON - Request body is not valid JSON

Business Logic (BUSINESS_*)

  • APPLICATION_NOT_FOUND - Referenced application doesn't exist
  • DUPLICATE_APPLICATION - Application already exists
  • INSUFFICIENT_BALANCE - Not enough funds available
  • APPLICATION_NOT_ELIGIBLE - Application status doesn't allow operation
  • LOAN_ALREADY_FUNDED - Loan has already been disbursed

System (SYSTEM_*)

  • INTERNAL_ERROR - Unexpected server error occurred
  • SERVICE_UNAVAILABLE - External service dependency failed
  • MAINTENANCE_MODE - System is in maintenance mode
  • RATE_LIMIT_EXCEEDED - Too many requests sent

File Operations (FILE_*)

  • FILE_TOO_LARGE - File exceeds size limit
  • INVALID_FILE_TYPE - File type not supported
  • FILE_UPLOAD_FAILED - File upload process failed
  • FILE_CORRUPTED - File appears to be corrupted