docs: protected <V> String performRequest(String url, String method, Map<String, V> params, Map<String, String> header, String payload) throws AuthenticationException, ApiException {
  		// Prepare header
  		if (header == null) {
  			header = new HashMap<String, String>();
  		}
  
  		// Set method
  		header.put("method", method.toUpperCase());
  
  		// Set 'User-Agent'
  		if (header.get("User-Agent") == null || header.get("User-Agent").isEmpty()) {
  			header.put("User-Agent", defaultUserAgent);
  		}
  
  		// Set 'Authorization'
  		if (this.basicAuthHash != null && !this.basicAuthHash.isEmpty()) {
  			if (header.get("Authorization") == null || header.get("Authorization").isEmpty()) {
  				header.put("Authorization", basicAuthHash);
  			}
  		}
  
  		// Set 'Content-Type'
  		if (header.get("Content-Type") == null || header.get("Content-Type").isEmpty()) {
  			header.put("Content-Type", defaultContentType);
  		}
  
  		// Set 'Accept'
  		if (header.get("Accept") == null || header.get("Accept").isEmpty()) {
  			header.put("Accept", defaultAccept);
  		}
  
  		// Prepare url
  		String realUrl = url;
  		if (params != null && !params.isEmpty()) {
  			realUrl += "?";
  			boolean isFirst = true;
  
  			for (Map.Entry<String, V> param : params.entrySet()) {
  				String key;
  				try {
  					key = URLEncoder.encode(param.getKey(), "UTF-8");
  					String realParam = GSON.fromJson(GSON.toJson(param.getValue()), String.class);
  					String val = URLEncoder.encode(realParam, "UTF-8");
  					if (!isFirst)
  						realUrl += "&";
  					realUrl += key + "=" + val;
  					isFirst = false;
  				} catch (UnsupportedEncodingException e) {
  					throw new ApiException("Wrong query parameter encoding for pair: " + param.getKey() + " = " + param.getValue(), e);
  				}
  
  			}
  		}
  
  		// Get connection
  		HttpURLConnection conn = openConnection(header, realUrl);
  
  		// Send Data if PUT/POST
  		if (payload != null) {
  			if (method.equalsIgnoreCase("PUT") || method.equalsIgnoreCase("POST")) {
  				OutputStream output = null;
  				try {
  					OutputStream outputStream = conn.getOutputStream();
  					IOUtils.write(payload, outputStream);
  				} catch (IOException e) {
  					throw new ApiException("Unable to send data to server", e);
  				} finally {
  					IOUtils.closeQuietly(output);
  				}
  			}
  		}
  
  		// Check Response code
  		int responseCode;
  		try {
  			responseCode = conn.getResponseCode();
  		} catch (IOException e) {
  			throw new ApiException("Unable to read response code", e);
  		}
  		
  		switch (responseCode) {
  		case HttpURLConnection.HTTP_UNAUTHORIZED:
  			throw new AuthenticationException("Invalid API credentials");
  		case HttpURLConnection.HTTP_BAD_REQUEST:
  			InputStream errorStream = conn.getErrorStream();
  			if (errorStream != null){
  				String error = readInputStream(errorStream);
  				throw new ApiException("Connection could not be made. Bad Request: " + error);
  			}else{
  				throw new ApiException("Connection could not be made. Bad Request");
  			}
  		}
  		
  		// Parse response
  		InputStream inputStream = null;
  		try {
  			inputStream = conn.getInputStream();
  			return readInputStream(inputStream);
  		} catch (IOException e) {
  			throw new ApiException("Unable to read response from server", e);
  		}finally{
  			IOUtils.closeQuietly(inputStream);
  		
  		}
  
  	}