diff --git a/.github/workflows/dependency-review.yml b/.github/workflows/dependency-review.yml
index fe461b42..b0dedc42 100644
--- a/.github/workflows/dependency-review.yml
+++ b/.github/workflows/dependency-review.yml
@@ -17,4 +17,4 @@ jobs:
       - name: 'Checkout Repository'
         uses: actions/checkout@v3
       - name: 'Dependency Review'
-        uses: actions/dependency-review-action@v2
+        uses: actions/dependency-review-action@v3
diff --git a/.github/workflows/java-ci.yml b/.github/workflows/java-ci.yml
index fc0f3be9..9397006d 100644
--- a/.github/workflows/java-ci.yml
+++ b/.github/workflows/java-ci.yml
@@ -5,6 +5,8 @@ on:
   pull_request:
     types: [ opened, reopened, synchronize ]
   workflow_dispatch:
+  schedule:
+    - cron: '0 */8 * * *'
 
 permissions:
   contents: write
@@ -118,5 +120,19 @@ jobs:
           configFile: ${{ github.workspace }}/src/test/resources/sauce-connect-config-apac-southeast.yaml
 
       - name: Build with Maven
+        id: runIntegrationTests
         if: ${{ env.NOT_FROM_FORK }} == 'true'
-        run: mvn clean test -Dtest="com.saucelabs.saucerest.integration.**" -Dgpg.skip -B -Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=warn -V
\ No newline at end of file
+        run: mvn clean test -Dtest="com.saucelabs.saucerest.integration.**" -Dgpg.skip -B -Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=warn -V
+
+  slackNotification:
+    name: Slack Notification
+    if: |
+      always() && (steps.runIntegrationTests.outcome == 'failure') &&
+      (${{  github.repository == github.event.pull_request.head.repo.full_name }} || ${{ github.event.push.head.repo.full_name == github.repository }})
+    runs-on: ubuntu-latest
+    steps:
+      - uses: actions/checkout@v2
+      - name: Slack Notification
+        uses: rtCamp/action-slack-notify@v2
+        env:
+          SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }}
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index 1c1c54e3..5caa2408 100644
--- a/pom.xml
+++ b/pom.xml
@@ -65,7 +65,7 @@
         <dependency>
             <groupId>org.json</groupId>
             <artifactId>json</artifactId>
-            <version>20220924</version>
+            <version>20230227</version>
         </dependency>
         <dependency>
             <groupId>commons-io</groupId>
@@ -283,7 +283,7 @@
             <plugin>
                 <groupId>org.apache.maven.plugins</groupId>
                 <artifactId>maven-compiler-plugin</artifactId>
-                <version>3.10.1</version>
+                <version>3.11.0</version>
                 <configuration>
                     <source>${java.version}</source>
                     <target>${java.version}</target>
@@ -308,6 +308,12 @@
                     </consoleOutputReporter>
                     <statelessTestsetInfoReporter
                         implementation="org.apache.maven.plugin.surefire.extensions.junit5.JUnit5StatelessTestsetInfoTreeReporter"/>
+                    <systemProperties>
+                        <property>
+                            <name>java.util.logging.config.file</name>
+                            <value>src/test/resources/logging.properties</value>
+                        </property>
+                    </systemProperties>
                 </configuration>
             </plugin>
         </plugins>
diff --git a/src/main/java/com/saucelabs/saucerest/ErrorExplainers.java b/src/main/java/com/saucelabs/saucerest/ErrorExplainers.java
index 0a861682..33e3ba71 100644
--- a/src/main/java/com/saucelabs/saucerest/ErrorExplainers.java
+++ b/src/main/java/com/saucelabs/saucerest/ErrorExplainers.java
@@ -11,10 +11,10 @@ public static String errorMessageBuilder(String errorReason, String errorExplana
 
     public static String missingCreds() {
         return String.join(System.lineSeparator(),
-            "If using System Properties/Environment Variables (ENVars), this can happen because:",
-            " * You are using a toolchain which does not automatically propagate ENVars between tools",
-            " * You are using a CI platform which does not automatically propagate ENVars between separate controller and processing hosts",
-            " * You are running tests on an environment on which these properties are not set; A newly build CI server, a Docker instance, etc"
+                "If using System Properties/Environment Variables (ENVars), this can happen because:",
+                " * You are using a toolchain which does not automatically propagate ENVars between tools",
+                " * You are using a CI platform which does not automatically propagate ENVars between separate controller and processing hosts",
+                " * You are running tests on an environment on which these properties are not set; A newly build CI server, a Docker instance, etc"
         );
     }
 
@@ -22,91 +22,117 @@ public static String incorrectCreds(String username, String accessKey) {
         String endOfKey = accessKey.substring(accessKey.length() - 3);
 
         return String.join(System.lineSeparator(),
-            "Not Authorized.  Possible Reasons:",
-            " * The provided Username (" + username + ") is incorrect",
-            " * This account does not have permissions to access this job",
-            " * The provided Access Key ending with '" + endOfKey + "' is incorrect"
+                "Not Authorized.  Possible Reasons:",
+                " * The provided Username (" + username + ") is incorrect",
+                " * This account does not have permissions to access this job",
+                " * The provided Access Key ending with '" + endOfKey + "' is incorrect"
         );
     }
 
     static String resourceMissing() {
         return String.join(System.lineSeparator(),
-            "Resource Not Found.   Possible reasons:",
-            " * This job does not exist",
-            " * Job assets have expired"
+                "Resource Not Found.   Possible reasons:",
+                " * This job does not exist",
+                " * Job assets have expired"
         );
     }
 
     static String videoMissing() {
         return String.join(System.lineSeparator(),
-            " * You disabled video recording by setting the `recordVideo` capability to false",
-            " * This test was not able to complete video encoding due to an error or early termination"
+                " * You disabled video recording by setting the `recordVideo` capability to false",
+                " * This test was not able to complete video encoding due to an error or early termination"
         );
     }
 
     static String HARMissing() {
         return String.join(System.lineSeparator(),
-            " * This test was run without Extended Debugging. See https://wiki.saucelabs.com/pages/viewpage.action?pageId=70072943",
-            " * This test was not able to complete HAR file recording due to an error or early termination"
+                " * This test was run without Extended Debugging. See https://wiki.saucelabs.com/pages/viewpage.action?pageId=70072943",
+                " * This test was not able to complete HAR file recording due to an error or early termination"
         );
     }
 
     public static String JobNotYetDone() {
         return String.join(System.lineSeparator(),
-            " * This job hasn't finished processing yet.",
-            " * After driver.quit() is called it will take some seconds to process and make available all job assets"
+                " * This job hasn't finished processing yet.",
+                " * After driver.quit() is called it will take some seconds to process and make available all job assets"
         );
     }
 
     static String LogNotFound() {
         return String.join(System.lineSeparator(),
-            " * Log file could not be found. Possible reasons:",
-            " * The requested log does not exist for the used framework. For example asking for the Selenium log when using Appium",
-            " * A error occurred where the job was created on Sauce Labs but no test were executed."
+                " * Log file could not be found. Possible reasons:",
+                " * The requested log does not exist for the used framework. For example asking for the Selenium log when using Appium",
+                " * A error occurred where the job was created on Sauce Labs but no test were executed."
         );
     }
 
     public static String TunnelNotFound() {
         return String.join(System.lineSeparator(),
-            " * Tunnel ID could not be found. Possible reasons:",
-            " * The tunnel ID requested does not exist in this data center. Ensure the data center endpoint is correct.",
-            " * A tunnel with this id never existed."
+                " * Tunnel ID could not be found. Possible reasons:",
+                " * The tunnel ID requested does not exist in this data center. Ensure the data center endpoint is correct.",
+                " * A tunnel with this id never existed."
         );
     }
 
     public static String TunnelNotFound(String tunnelID) {
         return String.join(System.lineSeparator(),
-            " * Tunnel ID " + tunnelID + " could not be found. Possible reasons:",
-            " * The tunnel ID requested does not exist in this data center. Ensure the data center endpoint is correct.",
-            " * A tunnel with this id never existed."
+                " * Tunnel ID " + tunnelID + " could not be found. Possible reasons:",
+                " * The tunnel ID requested does not exist in this data center. Ensure the data center endpoint is correct.",
+                " * A tunnel with this id never existed."
         );
     }
 
     public static String ResigningNotAllowed() {
         return String.join(System.lineSeparator(),
-            " * Trying to set Resigning for this app failed. Possible reason:",
-            " * You set the app platform to be Android. Resigning is only available and applied for iOS apps.",
-            " * Either use Instrumentation which is for Android apps or change the platform to iOS."
+                " * Trying to set Resigning for this app failed. Possible reason:",
+                " * You set the app platform to be Android. Resigning is only available and applied for iOS apps.",
+                " * Either use Instrumentation which is for Android apps or change the platform to iOS."
         );
     }
 
     public static String InstrumentationNotAllowed() {
         return String.join(System.lineSeparator(),
-            " * Trying to set Instrumentation for this app failed. Possible reason:",
-            " * You set the app platform to be iOS. Instrumentation is only available and applied for Android apps.",
-            " * Either use Resigning which is for iOS apps or change the platform to Android."
+                " * Trying to set Instrumentation for this app failed. Possible reason:",
+                " * You set the app platform to be iOS. Instrumentation is only available and applied for Android apps.",
+                " * Either use Resigning which is for iOS apps or change the platform to Android."
         );
     }
 
-  public static String DeviceLockOnlyOnAndroid() {
-    return String.join(System.lineSeparator(),
-      " * Trying to setup a PIN code is only available for Android devices."
-    );
-  }
+    public static String DeviceLockOnlyOnAndroid() {
+        return String.join(System.lineSeparator(),
+                " * Trying to setup a PIN code is only available for Android devices."
+        );
+    }
+
+    public static String NoResult() {
+        return String.join(System.lineSeparator(),
+                " * API request was successful but nothing found."
+        );
+    }
 
-  public static String NoResult() {
-    return String.join(System.lineSeparator(),
-      " * API request was successful but nothing found."
-    );
-  }
-}
+    public static String AppNotFound() {
+        return String.join(System.lineSeparator(),
+                "App or app group could not be found. Possible reasons:",
+                " * App was automatically deleted after 60 days",
+                " * App was deleted manually",
+                " * App was never uploaded",
+                " * App was uploaded to a different data center",
+                " * App was uploaded to a different account",
+                " * App was uploaded to a different team",
+                " * App was uploaded to a different user"
+        );
+    }
+
+    public static String AppNotFound(String fileID) {
+        return String.join(System.lineSeparator(),
+                "App or app group with ID " + fileID + " could not be found. Possible reasons:",
+                " * App was automatically deleted after 60 days",
+                " * App was deleted manually",
+                " * App was never uploaded",
+                " * App was uploaded to a different data center",
+                " * App was uploaded to a different account",
+                " * App was uploaded to a different team",
+                " * App was uploaded to a different user"
+        );
+    }
+}
\ No newline at end of file
diff --git a/src/main/java/com/saucelabs/saucerest/SauceREST.java b/src/main/java/com/saucelabs/saucerest/SauceREST.java
index 6456f8c1..a8267870 100644
--- a/src/main/java/com/saucelabs/saucerest/SauceREST.java
+++ b/src/main/java/com/saucelabs/saucerest/SauceREST.java
@@ -49,29 +49,16 @@ public class SauceREST implements Serializable {
      */
     private static final long HTTP_CONNECT_TIMEOUT_SECONDS = TimeUnit.SECONDS.toMillis(10);
     private static final int DEFAULT_BUILDS_LIMIT = 50;
-    /**
-     * The username to use when performing HTTP requests to the Sauce REST API.
-     */
-    protected String username;
-    /**
-     * The access key to use when performing HTTP requests to the Sauce REST API.
-     */
-    protected String accessKey;
-
     /**
      * Date format used as part of the file name for downloaded files.
      */
     private static final String DATE_FORMAT = "yyyyMMdd_HHmmSS";
-
     private static String extraUserAgent = "";
-
     private final String server;
     private final String apiServer;
     private final String edsServer;
     private final String appServer;
-
     private final String restApiEndpoint;
-
     /**
      * Retry policy default values.
      */
@@ -82,6 +69,14 @@ public class SauceREST implements Serializable {
     private final int delayFactor;
     private final ChronoUnit chronoUnit;
     private final List<Class<? extends Throwable>> throwableList;
+    /**
+     * The username to use when performing HTTP requests to the Sauce REST API.
+     */
+    protected String username;
+    /**
+     * The access key to use when performing HTTP requests to the Sauce REST API.
+     */
+    protected String accessKey;
 
     /**
      * Constructs a new instance of the SauceREST class.
@@ -134,6 +129,14 @@ public SauceREST(String username, String accessKey, DataCenter dataCenter, int m
         this.throwableList = throwableList;
     }
 
+    public static String getExtraUserAgent() {
+        return extraUserAgent;
+    }
+
+    public static void setExtraUserAgent(String extraUserAgent) {
+        SauceREST.extraUserAgent = extraUserAgent;
+    }
+
     /**
      * Build URL with environment variable, or system property, or default URL.
      *
@@ -155,62 +158,86 @@ private RetryPolicy<Object> getRetryPolicy() {
             .withBackoff(this.delay, this.maxDelay, this.chronoUnit, this.delayFactor);
     }
 
-    public static String getExtraUserAgent() {
-        return extraUserAgent;
+    public Job getJob(DataCenter dataCenter, String sessionId) {
+        return new Job(this.username, this.accessKey, dataCenter, sessionId);
     }
 
-    public static void setExtraUserAgent(String extraUserAgent) {
-        SauceREST.extraUserAgent = extraUserAgent;
+    public Job getJob(String sessionId) {
+        return new Job(this.username, this.accessKey, this.apiServer, sessionId);
     }
 
-    public Job getJob(DataCenter dataCenter, String sessionId) {
-        return new Job(dataCenter, sessionId);
+    public Job getJob(String apiServer, String sessionId) {
+        return new Job(this.username, this.accessKey, apiServer, sessionId);
     }
 
-    public Job getJob(String sessionId) {
-        return new Job(this.apiServer, sessionId);
+    public Storage getStorage() {
+        return new Storage(this.username, this.accessKey, this.apiServer);
     }
 
     public Storage getStorage(DataCenter dataCenter) {
-        return new Storage(dataCenter);
+        return new Storage(this.username, this.accessKey, dataCenter);
     }
 
-    public Storage getStorage() {
-        return new Storage(this.apiServer);
+    public Storage getStorage(String apiServer) {
+        return new Storage(this.username, this.accessKey, apiServer);
+    }
+
+    public Platform getPlatform() {
+        return new Platform(this.username, this.accessKey, this.apiServer);
     }
 
     public Platform getPlatform(DataCenter dataCenter) {
-        return new Platform(dataCenter);
+        return new Platform(this.username, this.accessKey, dataCenter);
     }
 
-    public Platform getPlatform() {
-        return new Platform(this.apiServer);
+    public Platform getPlatform(String apiServer) {
+        return new Platform(this.username, this.accessKey, apiServer);
     }
 
     public RealDevices getRealDevices(DataCenter dataCenter) {
-      return new RealDevices(dataCenter);
+        return new RealDevices(this.username, this.accessKey, dataCenter);
     }
 
-  public RealDevices getRealDevices() {
-    return new RealDevices(this.apiServer);
-  }
+    public RealDevices getRealDevices() {
+        return new RealDevices(this.username, this.accessKey, this.apiServer);
+    }
 
-  public SauceConnect getSauceConnect() {
-    return new SauceConnect(this.username, this.accessKey, this.apiServer);
-  }
+    public RealDevices getRealDevices(String apiServer) {
+        return new RealDevices(this.username, this.accessKey, apiServer);
+    }
 
-  public Accounts getAccounts() {
-    return new Accounts(this.username, this.accessKey, this.apiServer);
-  }
+    public SauceConnect getSauceConnect() {
+        return new SauceConnect(this.username, this.accessKey, this.apiServer);
+    }
 
-  /**
-   * Returns username assigned to this interface
-   *
-   * @return Returns username assigned to this interface
-   */
-  public String getUsername() {
-    return this.username;
-  }
+    public SauceConnect getSauceConnect(String apiServer) {
+        return new SauceConnect(this.username, this.accessKey, apiServer);
+    }
+
+    public SauceConnect getSauceConnect(DataCenter dataCenter) {
+        return new SauceConnect(this.username, this.accessKey, dataCenter);
+    }
+
+    public Accounts getAccounts() {
+        return new Accounts(this.username, this.accessKey, this.apiServer);
+    }
+
+    public Accounts getAccounts(String apiServer) {
+        return new Accounts(this.username, this.accessKey, apiServer);
+    }
+
+    public Accounts getAccounts(DataCenter dataCenter) {
+        return new Accounts(this.username, this.accessKey, dataCenter);
+    }
+
+    /**
+     * Returns username assigned to this interface
+     *
+     * @return Returns username assigned to this interface
+     */
+    public String getUsername() {
+        return this.username;
+    }
 
     /**
      * Returns server assigned to this interface
@@ -1021,14 +1048,14 @@ public String getJobs(int limit, long to, int from) {
     /**
      * Returns a String (in JSON format) representing the details for Sauce jobs.
      *
-     * @param ids   iterable of job ids
-     * @param full  should return full jobs response
+     * @param ids  iterable of job ids
+     * @param full should return full jobs response
      * @return String (in JSON format) representing the jobID for sauce jobs
      * @deprecated
      */
     public String getJobsByIds(Iterable<String> ids, boolean full) {
         List<String> params = new ArrayList<String>();
-        for (String jobId: ids) {
+        for (String jobId : ids) {
             params.add("id=" + jobId);
         }
         if (params.size() == 0) {
@@ -1044,7 +1071,7 @@ public String getJobsByIds(Iterable<String> ids, boolean full) {
     /**
      * Returns a String (in JSON format) representing the details for Sauce jobs.
      *
-     * @param ids   iterable of job ids
+     * @param ids iterable of job ids
      * @return String (in JSON format) representing the jobID for full sauce jobs
      * @deprecated
      */
@@ -1107,7 +1134,7 @@ private BufferedInputStream downloadAssetData(String jobId, TestAsset assetName)
      * @throws IOException                  when something goes wrong fetching the data
      */
     private BufferedInputStream downloadFileData(String jobId, URL restEndpoint) throws SauceException.NotAuthorized, IOException {
-        logger.log(Level.FINE, "Downloading asset {0} For Job {1}", new Object[] { restEndpoint, jobId });
+        logger.log(Level.FINE, "Downloading asset {0} For Job {1}", new Object[]{restEndpoint, jobId});
         logger.log(Level.FINEST, "Opening connection for Job {0}", jobId);
 
         HttpURLConnection connection = null;
@@ -1135,7 +1162,7 @@ private HttpURLConnection setConnection(String jobId, URL restEndpoint, HttpMeth
         HttpURLConnection connection = openConnection(method, restEndpoint);
 
         int responseCode = connection.getResponseCode();
-        logger.log(Level.FINEST, "{0} - {1} for: {2}", new Object[] { responseCode, restEndpoint, jobId });
+        logger.log(Level.FINEST, "{0} - {1} for: {2}", new Object[]{responseCode, restEndpoint, jobId});
         switch (responseCode) {
             case HttpURLConnection.HTTP_NOT_FOUND:
 
@@ -1236,12 +1263,12 @@ private String getDefaultFileName(String jobId, String overwriteFilename) {
 
     private void saveFileOrThrowException(String jobId, String location, String fileName, URL restEndpoint) throws SauceException.NotAuthorized, IOException {
         logger.log(Level.FINEST, "Attempting to save asset {0} for Job {1} to {2}",
-            new Object[] { restEndpoint, jobId, location });
+            new Object[]{restEndpoint, jobId, location});
 
         fileName = getFileName(fileName, jobId, restEndpoint);
         File targetFile = new File(location, fileName);
         System.out.println("Saving " + restEndpoint + " for Job " + jobId + " as " + targetFile);
-        logger.log(Level.FINEST, "Saving {0} for Job {1} as {2}", new Object[] { restEndpoint, jobId, targetFile });
+        logger.log(Level.FINEST, "Saving {0} for Job {1} as {2}", new Object[]{restEndpoint, jobId, targetFile});
 
         try (BufferedInputStream in = downloadFileData(jobId, restEndpoint)) {
             FileUtils.copyInputStreamToFile(in, targetFile);
@@ -1262,7 +1289,7 @@ private void saveFileOrThrowException(String jobId, String location, String file
      */
     private void saveServerLogFileOrThrow(String jobId, String location, String fileName, URL restEndpoint) throws SauceException.NotAuthorized, IOException {
         logger.log(Level.FINEST, "Attempting to save asset {0} for Job {1} to {2}",
-            new Object[] { restEndpoint, jobId, location });
+            new Object[]{restEndpoint, jobId, location});
         byte[] bytes;
         try (BufferedInputStream in = downloadFileData(jobId, restEndpoint)) {
             bytes = IOUtils.toByteArray(in);
@@ -1277,7 +1304,7 @@ private void saveServerLogFileOrThrow(String jobId, String location, String file
         }
 
         File targetFile = new File(location, fileName);
-        logger.log(Level.FINEST, "Saving {0} for Job {1} as {2}", new Object[] { restEndpoint, jobId, targetFile });
+        logger.log(Level.FINEST, "Saving {0} for Job {1} as {2}", new Object[]{restEndpoint, jobId, targetFile});
 
         FileUtils.writeByteArrayToFile(targetFile, bytes);
     }
@@ -1405,7 +1432,7 @@ public HttpURLConnection openConnection(URL url) throws IOException {
         HttpURLConnection con;
         if ("true".equals(System.getenv("USE_PROXY"))) {
             logger.log(Level.SEVERE, "Using proxy: {0}:{1}",
-                new Object[] { System.getenv("http.proxyHost"), System.getenv("http.proxyPort") });
+                new Object[]{System.getenv("http.proxyHost"), System.getenv("http.proxyPort")});
 
             Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(System.getenv("http.proxyHost"),
                 Integer.parseInt(System.getenv("http.proxyPort"))));
@@ -1424,6 +1451,7 @@ public HttpURLConnection openConnection(URL url) throws IOException {
      * RFC 2616: https://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9
      * However, to better prevent typos and errors we opt to use an Enum and live with the possibility to have to extend it
      * should the specification change.
+     *
      * @param method
      * @param url
      * @return
@@ -1551,7 +1579,7 @@ public String getUser() {
      * Retrieve jobs associated with a build
      *
      * @param source JobSource enum
-     * @param build Build ID
+     * @param build  Build ID
      * @return String (in JSON format) representing jobs associated with a build
      */
     public String getBuildJobs(JobSource source, String build) {
@@ -1563,7 +1591,7 @@ public String getBuildJobs(JobSource source, String build) {
      * Retrieve build info
      *
      * @param source JobSource enum
-     * @param build Build ID
+     * @param build  Build ID
      * @return String (in JSON format) representing the build
      */
     public String getBuild(JobSource source, String build) {
@@ -1585,7 +1613,7 @@ public String getBuilds(JobSource source) {
      * Retrieve recent builds
      *
      * @param source JobSource enum
-     * @param limit Max number of builds returned
+     * @param limit  Max number of builds returned
      * @return String (in JSON format) representing the latest builds
      */
     public String getBuilds(JobSource source, int limit) {
@@ -1597,7 +1625,7 @@ public String getBuilds(JobSource source, int limit) {
      * Retrieve recent builds
      *
      * @param source JobSource enum
-     * @param jobId the Sauce job ID, typically equal to the Selenium/WebDriver sessionId
+     * @param jobId  the Sauce job ID, typically equal to the Selenium/WebDriver sessionId
      * @return String (in JSON format) representing the latest builds
      */
     public String getBuildForJob(JobSource source, String jobId) {
@@ -1609,7 +1637,7 @@ public String getBuildForJob(JobSource source, String jobId) {
      * Retrieve builds by name
      *
      * @param source JobSource enum
-     * @param name Name of desired builds
+     * @param name   Name of desired builds
      * @return String (in JSON format) representing the latest builds
      */
     public String getBuildsByName(JobSource source, String name) throws java.io.UnsupportedEncodingException {
@@ -1620,8 +1648,8 @@ public String getBuildsByName(JobSource source, String name) throws java.io.Unsu
      * Retrieve builds by name
      *
      * @param source JobSource enum
-     * @param name Name of desired builds
-     * @param limit Max number of builds returned
+     * @param name   Name of desired builds
+     * @param limit  Max number of builds returned
      * @return String (in JSON format) representing the latest builds
      */
     public String getBuildsByName(JobSource source, String name, int limit) throws java.io.UnsupportedEncodingException {
@@ -1673,4 +1701,4 @@ public boolean equals(Object obj) {
     private interface IOExecutable {
         void execute() throws IOException;
     }
-}
+}
\ No newline at end of file
diff --git a/src/main/java/com/saucelabs/saucerest/api/AbstractEndpoint.java b/src/main/java/com/saucelabs/saucerest/api/AbstractEndpoint.java
index 6785f4b2..52baeb74 100644
--- a/src/main/java/com/saucelabs/saucerest/api/AbstractEndpoint.java
+++ b/src/main/java/com/saucelabs/saucerest/api/AbstractEndpoint.java
@@ -2,6 +2,7 @@
 
 import com.saucelabs.saucerest.BuildUtils;
 import com.saucelabs.saucerest.DataCenter;
+import com.saucelabs.saucerest.HttpMethod;
 import com.saucelabs.saucerest.model.AbstractModel;
 import com.squareup.moshi.JsonAdapter;
 import com.squareup.moshi.Moshi;
@@ -100,7 +101,7 @@ public String getResponseObject(String url) throws IOException {
      * @return
      * @throws IOException
      */
-    public String getResponseObject(String url, Map<String, Object> params) throws IOException {
+    public Response getResponseObject(String url, Map<String, Object> params) throws IOException {
         HttpUrl.Builder urlBuilder = HttpUrl.parse(url).newBuilder();
 
         for (Map.Entry<String, Object> param : params.entrySet()) {
@@ -114,20 +115,7 @@ public String getResponseObject(String url, Map<String, Object> params) throws I
             }
         }
 
-        Request.Builder chain = new Request.Builder();
-
-        if (credentials != null) {
-            chain = chain.header("Authorization", credentials);
-        }
-
-        Request request = chain
-            .header("User-Agent", userAgent)
-            .url(urlBuilder.build().toString())
-            .build();
-
-        try (Response response = makeRequest(request)) {
-            return response.body().string();
-        }
+        return request(urlBuilder.build().toString(), HttpMethod.GET);
     }
 
     public okio.BufferedSource getStream(String url) throws IOException {
@@ -135,70 +123,7 @@ public okio.BufferedSource getStream(String url) throws IOException {
         return response.body().source();
     }
 
-    public String postResponse(String url, Map<String, Object> payload) throws IOException {
-        return postResponse(url, payload, MediaType.parse("application/json"));
-    }
-
-    public String postResponse(String url, Map<String, Object> payload, MediaType mediaType) throws IOException {
-        String json = new JSONObject(payload).toString();
-
-        Request.Builder chain = new Request.Builder();
-
-        if (credentials != null) {
-            chain = chain.header("Authorization", credentials);
-        }
-
-        Request request = chain
-            .header("User-Agent", userAgent)
-            .url(url)
-            .post(RequestBody.create(json, mediaType))
-            .build();
-
-        try (Response response = makeRequest(request)) {
-            return response.body().string();
-        }
-    }
-
-    public String postResponse(String url) throws IOException {
-        Request.Builder chain = new Request.Builder();
-
-        if (credentials != null) {
-            chain = chain.header("Authorization", credentials);
-        }
-
-        Request request = chain
-            .header("User-Agent", userAgent)
-            .url(url)
-            .post(RequestBody.create("", MediaType.parse("application/json")))
-            .build();
-
-        try (Response response = makeRequest(request)) {
-            return response.body().string();
-        }
-    }
-
-    public String putResponse(String url, Map<String, Object> payload) throws IOException {
-        String json = new JSONObject(payload).toString();
-
-        Request.Builder chain = new Request.Builder();
-
-        if (credentials != null) {
-            chain = chain.header("Authorization", credentials);
-        }
-
-        Request request = chain
-            .url(url)
-            .put(RequestBody.create(json, MediaType.parse("application/json")))
-            .build();
-
-        try (Response response = makeRequest(request)) {
-            return response.body().string();
-        }
-    }
-
-    public String putResponse(String url, String payload) throws IOException {
-        String json = new JSONObject(payload).toString();
-
+    private Response getResponse(String url) throws IOException {
         Request.Builder chain = new Request.Builder();
 
         if (credentials != null) {
@@ -207,74 +132,42 @@ public String putResponse(String url, String payload) throws IOException {
 
         Request request = chain
             .url(url)
-            .put(RequestBody.create(json, MediaType.parse("application/json")))
+            .get()
             .build();
 
-        try (Response response = makeRequest(request)) {
-            return response.body().string();
-        }
+        return makeRequest(request);
     }
 
-    public String patchResponse(String url, Map<String, Object> payload) throws IOException {
-        String json = new JSONObject(payload).toString();
-
-        Request.Builder chain = new Request.Builder();
-
-        if (credentials != null) {
-            chain = chain.header("Authorization", credentials);
-        }
-
-        Request request = chain
-            .url(url)
-            .patch(RequestBody.create(json, MediaType.parse("application/json")))
-            .build();
-
-        try (Response response = makeRequest(request)) {
-            return response.body().string();
-        }
+    public Response request(String url, HttpMethod httpMethod) throws IOException {
+        return request(url, httpMethod, (String) null);
     }
 
-    public String patchResponse(String url, String payload) throws IOException {
-        String json = new JSONObject(payload).toString();
-
-        Request.Builder chain = new Request.Builder();
-
-        if (credentials != null) {
-            chain = chain.header("Authorization", credentials);
-        }
-
-        Request request = chain
-            .url(url)
-            .patch(RequestBody.create(json, MediaType.parse("application/json")))
-            .build();
-
-        try (Response response = makeRequest(request)) {
-            return response.body().string();
-        }
+    public Response request(String url, HttpMethod httpMethod, Map<String, Object> body) throws IOException {
+        return request(url, httpMethod, new JSONObject(body).toString());
     }
 
-    public String deleteResponse(String url) throws IOException {
+    public Response request(String url, HttpMethod httpMethod, String body) throws IOException {
         Request.Builder chain = new Request.Builder();
 
         if (credentials != null) {
-            chain = chain.header("Authorization", credentials);
+            chain.header("Authorization", credentials);
         }
 
-        Request request = chain
-            .url(url)
-            .delete()
-            .build();
-
-        try (Response response = makeRequest(request)) {
-            return response.body().string();
-        }
-    }
-
-    private Response getResponse(String url) throws IOException {
-        Request.Builder chain = new Request.Builder();
-
-        if (credentials != null) {
-            chain = chain.header("Authorization", credentials);
+        if (body != null) {
+            if (body.equals("")) {
+                chain.method(httpMethod.label, RequestBody.create(body, MediaType.parse("application/json")));
+            } else {
+                String json = new JSONObject(body).toString();
+                chain.method(httpMethod.label, RequestBody.create(json, MediaType.parse("application/json")));
+            }
+        } else {
+            if (httpMethod.equals(HttpMethod.GET)) {
+                chain.method(httpMethod.label, null);
+            } else if (httpMethod.equals(HttpMethod.POST)) {
+                chain.method(httpMethod.label, RequestBody.create(null, "application/json"));
+            } else {
+                chain.method(httpMethod.label, null);
+            }
         }
 
         Request request = chain
@@ -300,30 +193,47 @@ protected Response makeRequest(Request request) throws IOException {
             Response finalResponse = response;
             response = Failsafe.with(
                     new RetryPolicy<>()
-                        .handle(RuntimeException.class)
-                        .withBackoff(30, 500, ChronoUnit.MILLIS)
+                        .handle(RuntimeException.class, IOException.class, IllegalStateException.class)
+                        .withBackoff(30, 500, ChronoUnit.SECONDS)
                         .withMaxRetries(2)
                         .onRetry(e -> logger.log(Level.WARNING, () -> "Retrying because of " + finalResponse.code())))
                 .get(() -> client.newCall(request).execute());
         }
 
         if (!response.isSuccessful()) {
+            Response finalResponse1 = response;
+            logger.log(Level.INFO, () -> "Request " + request.method() + " " + request.url() + " failed with response code " + finalResponse1.code() + " and message " + finalResponse1.message());
             responseHandler(this, response);
         }
         return response;
     }
 
-    protected <T> T getResponseClass(String jsonResponse, Class<T> clazz) throws IOException {
+    /**
+     * This method is used to deserialize a JSON object response from an API endpoint.
+     *
+     * @param jsonResponse JSON object response from API endpoint
+     * @param clazz        The class to deserialize the JSON object into
+     * @param <T>          The type of the object to deserialize
+     * @return The deserialized object
+     * @throws IOException If the JSON object cannot be deserialized
+     */
+    protected <T> T deserializeJSONObject(String jsonResponse, Class<T> clazz) throws IOException {
         Moshi moshi = new Moshi.Builder().build();
-        // failOnUnknown() will make sure that API changes in SL are caught ASAP so we can update SauceREST
+        // failOnUnknown() will make sure that API changes in SL are caught ASAP, so we can update SauceREST
         JsonAdapter<T> jsonAdapter = moshi.adapter(clazz).failOnUnknown();
         return jsonAdapter.fromJson(jsonResponse);
     }
 
     /**
-     * Need to use this as the response is a JSON array instead of a JSON object.
+     * This method is used to deserialize a JSON array response from an API endpoint.
+     *
+     * @param jsonResponse JSON array response from API endpoint
+     * @param clazz        The class to deserialize the JSON array into
+     * @param <T>          The type of the object to deserialize
+     * @return The deserialized list of objects
+     * @throws IOException If the JSON array cannot be deserialized
      */
-    protected <T> List<T> getResponseListClass(String jsonResponse, Class<T> clazz) throws IOException {
+    protected <T> List<T> deserializeJSONArray(String jsonResponse, Class<T> clazz) throws IOException {
         Moshi moshi = new Moshi.Builder().build();
 
         Type listPlatform = Types.newParameterizedType(List.class, clazz);
diff --git a/src/main/java/com/saucelabs/saucerest/api/Accounts.java b/src/main/java/com/saucelabs/saucerest/api/Accounts.java
index 03c1bcd9..0df30198 100644
--- a/src/main/java/com/saucelabs/saucerest/api/Accounts.java
+++ b/src/main/java/com/saucelabs/saucerest/api/Accounts.java
@@ -2,7 +2,9 @@
 
 import com.google.common.collect.ImmutableMap;
 import com.saucelabs.saucerest.DataCenter;
+import com.saucelabs.saucerest.HttpMethod;
 import com.saucelabs.saucerest.model.accounts.*;
+import okhttp3.Response;
 
 import java.io.IOException;
 import java.util.List;
@@ -44,7 +46,7 @@ protected String getBaseEndpoint() {
     public LookupTeams lookupTeams() throws IOException {
         String url = getBaseEndpoint() + "teams/";
 
-        return getResponseClass(getResponseObject(url), LookupTeams.class);
+        return deserializeJSONObject(getResponseObject(url), LookupTeams.class);
     }
 
     /**
@@ -55,7 +57,7 @@ public LookupTeams lookupTeams() throws IOException {
     public LookupTeams lookupTeams(String name) throws IOException {
         String url = getBaseEndpoint() + "teams?name=" + name;
 
-        return getResponseClass(getResponseObject(url), LookupTeams.class);
+        return deserializeJSONObject(getResponseObject(url), LookupTeams.class);
     }
 
     /**
@@ -68,7 +70,7 @@ public LookupTeams lookupTeams(String name) throws IOException {
     public Team getSpecificTeam(String teamID) throws IOException {
         String url = getBaseEndpoint() + "teams/" + teamID;
 
-        return getResponseClass(getResponseObject(url), Team.class);
+        return deserializeJSONObject(getResponseObject(url), Team.class);
     }
 
     /**
@@ -86,25 +88,30 @@ public CreateTeam createTeam(String name, Settings settings, String description)
         String url = getBaseEndpoint() + "teams/";
         Map map = ImmutableMap.of("name", name, "settings", settings, "description", description);
 
-        return getResponseClass(postResponse(url, map), CreateTeam.class);
+        return deserializeJSONObject(request(url, HttpMethod.POST, map).body().string(), CreateTeam.class);
+    }
+
+    public CreateTeam createTeam(String name, Integer VMConcurrency, String description) throws IOException {
+        return createTeam(name, new Settings.Builder().setVirtualMachines(VMConcurrency).build(), description);
     }
 
     public Organizations getOrganization() throws IOException {
         String url = getBaseEndpoint() + "organizations";
 
-        return getResponseClass(getResponseObject(url), Organizations.class);
+        return deserializeJSONObject(getResponseObject(url), Organizations.class);
     }
 
     /**
      * Deletes the specified team from the organization of the requesting account.
      *
      * @param teamID The unique identifier of the team. You can look up the IDs of teams in your organization using the {@link LookupTeams} endpoint.
+     * @return
      * @throws IOException API request failed
      */
-    public void deleteTeam(String teamID) throws IOException {
+    public Response deleteTeam(String teamID) throws IOException {
         String url = getBaseEndpoint() + "teams/" + teamID;
 
-        deleteResponse(url);
+        return request(url, HttpMethod.DELETE);
     }
 
     /**
@@ -123,7 +130,7 @@ public UpdateTeam updateTeam(String teamID, String name, Settings settings, Stri
         String url = getBaseEndpoint() + "teams/" + teamID;
         Map map = ImmutableMap.of("name", name, "settings", settings, "description", description);
 
-        return getResponseClass(putResponse(url, map), UpdateTeam.class);
+        return deserializeJSONObject(request(url, HttpMethod.PUT, map).body().string(), UpdateTeam.class);
     }
 
     /**
@@ -137,7 +144,7 @@ public UpdateTeam updateTeam(String teamID, String name, Settings settings, Stri
     public UpdateTeam partiallyUpdateTeam(String teamID, UpdateTeam updateTeam) throws IOException {
         String url = getBaseEndpoint() + "teams/" + teamID;
 
-        return getResponseClass(patchResponse(url, updateTeam.toJson()), UpdateTeam.class);
+        return deserializeJSONObject(request(url, HttpMethod.PATCH, updateTeam.toJson()).body().string(), UpdateTeam.class);
     }
 
     /**
@@ -150,7 +157,7 @@ public UpdateTeam partiallyUpdateTeam(String teamID, UpdateTeam updateTeam) thro
     public TeamMembers getTeamMembers(String teamID) throws IOException {
         String url = getBaseEndpoint() + "teams/" + teamID + "/members";
 
-        return getResponseClass(getResponseObject(url), TeamMembers.class);
+        return deserializeJSONObject(getResponseObject(url), TeamMembers.class);
     }
 
     /**
@@ -163,7 +170,7 @@ public TeamMembers getTeamMembers(String teamID) throws IOException {
     public List<ResetAccessKeyForTeam> resetAccessKeyForTeam(String teamID) throws IOException {
         String url = getBaseEndpoint() + "teams/" + teamID + "/reset-access-key";
 
-        return getResponseListClass(postResponse(url), ResetAccessKeyForTeam.class);
+        return deserializeJSONArray(request(url, HttpMethod.POST, "").body().string(), ResetAccessKeyForTeam.class);
     }
 
     /**
@@ -175,7 +182,7 @@ public List<ResetAccessKeyForTeam> resetAccessKeyForTeam(String teamID) throws I
     public LookupUsers lookupUsers() throws IOException {
         String url = getBaseEndpoint() + "users/";
 
-        return getResponseClass(getResponseObject(url), LookupUsers.class);
+        return deserializeJSONObject(getResponseObject(url), LookupUsers.class);
     }
 
     /**
@@ -188,7 +195,7 @@ public LookupUsers lookupUsers() throws IOException {
     public LookupUsers lookupUsers(LookupUsersParameter lookupUsersParameter) throws IOException {
         String url = getBaseEndpoint() + "users/";
 
-        return getResponseClass(getResponseObject(url, lookupUsersParameter.toMap()), LookupUsers.class);
+        return deserializeJSONObject(getResponseObject(url, lookupUsersParameter.toMap()).body().string(), LookupUsers.class);
     }
 
     /**
@@ -201,6 +208,182 @@ public LookupUsers lookupUsers(LookupUsersParameter lookupUsersParameter) throws
     public User getUser(String userID) throws IOException {
         String url = getBaseEndpoint() + "users/" + userID;
 
-        return getResponseClass(getResponseObject(url), User.class);
+        return deserializeJSONObject(getResponseObject(url), User.class);
+    }
+
+    /**
+     * Creates a new user in the Sauce Labs platform.
+     *
+     * @param createUser {@link CreateUser}
+     * @return {@link User}
+     * @throws IOException API request failed
+     */
+    public User createUser(CreateUser createUser) throws IOException {
+        String url = getBaseEndpoint() + "users/";
+
+        return deserializeJSONObject(request(url, HttpMethod.POST, createUser.toMap()).body().string(), User.class);
+    }
+
+    /**
+     * Replaces all values of the specified user profile with the new set of parameters passed in the request. To update only certain parameters, see Partially Update a User.
+     *
+     * @param updateUser {@link UpdateUser}
+     * @return {@link User}
+     * @throws IOException API request failed
+     */
+    public User updateUser(UpdateUser updateUser) throws IOException {
+        String url = getBaseEndpoint() + "users/" + updateUser.userID;
+
+        return deserializeJSONObject(request(url, HttpMethod.PUT, updateUser.toMap()).body().string(), User.class);
+    }
+
+    /**
+     * Allows you to update individual user values without replacing the entire profile.
+     *
+     * @param updateUser {@link UpdateUser}
+     * @return {@link User}
+     * @throws IOException API request failed
+     */
+    public User partiallyUpdateUser(UpdateUser updateUser) throws IOException {
+        String url = getBaseEndpoint() + "users/" + updateUser.userID;
+
+        return deserializeJSONObject(request(url, HttpMethod.PATCH, updateUser.toMap()).body().string(), User.class);
+    }
+
+    /**
+     * Returns details about the current in-use virtual machines and real devices along with the maximum allowed values. <br> <br>
+     * NOTE:
+     * At this time, the current usage for real devices is not accurately returned in the response. As a workaround, use the following endpoint: {@link RealDevices#getConcurrency()}
+     *
+     * @param username The username of the user whose concurrency you are looking up. You can look up a user's name using a variety of filtering parameters with the {@link LookupUsers} endpoint.
+     * @return {@link UserConcurrency}
+     * @throws IOException API request failed
+     */
+    public UserConcurrency getUserConcurrency(String username) throws IOException {
+        String url = super.getBaseEndpoint() + "rest/v1.2/users/" + username + "/concurrency";
+
+        return deserializeJSONObject(request(url, HttpMethod.GET).body().string(), UserConcurrency.class);
+    }
+
+    /**
+     * Returns the number of teams a user belongs to and provides information about each team, including whether it is the default and its concurrency settings.
+     *
+     * @param userID The unique identifier of the user. You can look up a user's ID using the {@link LookupUsers} endpoint.
+     * @return {@link UsersTeam}
+     * @throws IOException API request failed
+     */
+    public UsersTeam getUsersTeam(String userID) throws IOException {
+        String url = getBaseEndpoint() + "users/" + userID + "/teams/";
+
+        return deserializeJSONObject(request(url, HttpMethod.GET).body().string(), UsersTeam.class);
+    }
+
+    /**
+     * Set a user's team affiliation. Users are limited to one team affiliation, so if the user is already a member of a different team, this call will remove them from that team.
+     * Also, By default, the user will not have team-admin privileges, even if they did on a prior team.
+     *
+     * @param userID The unique identifier of the Sauce Labs user to be added to the team.You can look up the ID of a user in your organization using the {@link LookupUsers} endpoint.
+     * @param teamID The identifier of the team to which the user will be added. You can look up the ID of a team in your organization using the {@link LookupTeams} endpoint.
+     * @return {@link User}
+     * @throws IOException API request failed
+     */
+    public SetTeam setUsersTeam(String userID, String teamID) throws IOException {
+        String url = getBaseEndpoint() + "membership";
+
+        Map map = ImmutableMap.of("user", userID, "team", teamID);
+
+        return deserializeJSONObject(request(url, HttpMethod.POST, map).body().string(), SetTeam.class);
+    }
+
+    /**
+     * Assigns administrator rights to the user within their organization. Organization Admins automatically have Team Admin rights in all the teams in the Organization.
+     *
+     * @param userID The unique identifier of the user. You can look up a user's ID using the {@link LookupUsers} endpoint.
+     * @return {@link User}
+     * @throws IOException API request failed
+     */
+    public User setAdmin(String userID) throws IOException {
+        String url = getBaseEndpoint() + "users/" + userID + "/set-admin";
+
+        return deserializeJSONObject(request(url, HttpMethod.POST).body().string(), User.class);
+    }
+
+    /**
+     * Assigns team administrator rights to the user within their current team. If the user is currently assigned an Org Admin role, this call would reduce the rights to only those of a Team Admin.
+     *
+     * @param userID The unique identifier of the user. You can look up a user's ID using the {@link LookupUsers} endpoint.
+     * @return {@link User}
+     * @throws IOException API request failed
+     */
+    public User setTeamAdmin(String userID) throws IOException {
+        String url = getBaseEndpoint() + "users/" + userID + "/set-team-admin";
+
+        return deserializeJSONObject(request(url, HttpMethod.POST).body().string(), User.class);
+    }
+
+    /**
+     * Assigns the member role to the user. If the user is currently assigned any Admin rights, this call removes those rights.
+     *
+     * @param userID The unique identifier of the user. You can look up a user's ID using the {@link LookupUsers} endpoint.
+     * @return {@link User}
+     * @throws IOException API request failed
+     */
+    public User setMember(String userID) throws IOException {
+        String url = getBaseEndpoint() + "users/" + userID + "/set-member";
+
+        return deserializeJSONObject(request(url, HttpMethod.POST).body().string(), User.class);
+    }
+
+    /**
+     * Retrieves the Sauce Labs access key for the specified user.
+     *
+     * @param userID The unique identifier of the user. You can look up a user's ID using the {@link LookupUsers} endpoint.
+     * @return {@link User}
+     * @throws IOException API request failed
+     */
+    public User getAccessKey(String userID) throws IOException {
+        String url = getBaseEndpoint() + "users/" + userID + "/access-key";
+
+        return deserializeJSONObject(request(url, HttpMethod.GET).body().string(), User.class);
+    }
+
+    /**
+     * Creates a new auto-generated access key for the specified user. <br> <br>
+     * Regenerating an access key invalidates the previous value and any tests containing the prior value will fail, so make sure you update any tests and credential environment variables with the new value.
+     *
+     * @param userID The unique identifier of the user. You can look up a user's ID using the {@link LookupUsers} endpoint.
+     * @return {@link User}
+     * @throws IOException API request failed
+     */
+    public List<User> resetAccessKey(String userID) throws IOException {
+        String url = getBaseEndpoint() + "users/" + userID + "/reset-access-key";
+
+        return deserializeJSONArray(request(url, HttpMethod.POST).body().string(), User.class);
+    }
+
+    /**
+     * Suspends the specified user's account, preventing all access to Sauce Labs while deactivated.
+     *
+     * @param userID The unique identifier of the user. You can look up a user's ID using the {@link LookupUsers} endpoint.
+     * @return {@link User}
+     * @throws IOException API request failed
+     */
+    public User deactivateUser(String userID) throws IOException {
+        String url = getBaseEndpoint() + "users/" + userID + "/deactivate";
+
+        return deserializeJSONObject(request(url, HttpMethod.POST).body().string(), User.class);
+    }
+
+    /**
+     * Re-activates the specified user's account, if it had been previously deactivated.
+     *
+     * @param userID The unique identifier of the user. You can look up a user's ID using the {@link LookupUsers} endpoint.
+     * @return {@link User}
+     * @throws IOException API request failed
+     */
+    public User activateUser(String userID) throws IOException {
+        String url = getBaseEndpoint() + "users/" + userID + "/activate";
+
+        return deserializeJSONObject(request(url, HttpMethod.POST).body().string(), User.class);
     }
 }
\ No newline at end of file
diff --git a/src/main/java/com/saucelabs/saucerest/api/Job.java b/src/main/java/com/saucelabs/saucerest/api/Job.java
index d7ad8c43..3de59d25 100644
--- a/src/main/java/com/saucelabs/saucerest/api/Job.java
+++ b/src/main/java/com/saucelabs/saucerest/api/Job.java
@@ -2,6 +2,7 @@
 
 import com.google.common.collect.ImmutableMap;
 import com.saucelabs.saucerest.DataCenter;
+import com.saucelabs.saucerest.HttpMethod;
 import com.saucelabs.saucerest.JobVisibility;
 import com.saucelabs.saucerest.TestAsset;
 import okio.BufferedSink;
@@ -30,14 +31,14 @@ public Job(String apiServer, String sessionId) {
         this.jobID = sessionId;
     }
 
-    public Job(String username, String accessKey, DataCenter dataCenter, String jobID) {
+    public Job(String username, String accessKey, DataCenter dataCenter, String sessionId) {
         super(username, accessKey, dataCenter);
-        this.jobID = jobID;
+        this.jobID = sessionId;
     }
 
-    public Job(String username, String accessKey, String apiServer, String jobID) {
+    public Job(String username, String accessKey, String apiServer, String sessionId) {
         super(username, accessKey, apiServer);
-        this.jobID = jobID;
+        this.jobID = sessionId;
     }
 
     public JSONObject getDetails() throws IOException {
@@ -81,13 +82,13 @@ public JSONObject addCustomData(Map<String, Object> customData) throws IOExcepti
     public JSONObject stop() throws IOException {
         String url = getBaseEndpoint() + "/stop";
 
-        return new JSONObject(putResponse(url, new HashMap<>()));
+        return new JSONObject(request(url, HttpMethod.PUT, new HashMap<>()).body().string());
     }
 
     // Note: This works, but docs indicate it should be /rest/v1.1/jobs/{job_id} which doesn't work
     public void delete() throws IOException {
         waitForFinishedTest();
-        deleteResponse(getBaseEndpoint());
+        request(getBaseEndpoint(), HttpMethod.DELETE);
     }
 
     public JSONObject availableAssets() throws IOException {
@@ -120,19 +121,17 @@ public void downloadAllAssets(Path location, String prepend) throws IOException
         JSONObject jsonObject = availableAssets();
         jsonObject.toMap().values().stream()
             .map(asset -> asset instanceof ArrayList ? "screenshots.zip" : (String) asset)
-            .forEach((assetName) -> {
-                downloadKnownAsset(TestAsset.get(assetName).get(), location, prepend);
-            });
+            .forEach((assetName) -> downloadKnownAsset(TestAsset.get(assetName).get(), location, prepend));
     }
 
     public void deleteAllAssets() throws IOException {
         String url = getBaseEndpoint() + "/assets";
 
-        deleteResponse(url);
+        request(url, HttpMethod.DELETE);
     }
 
     private JSONObject updateDetails(Map<String, Object> updates) throws IOException {
-        return new JSONObject(putResponse(getBaseEndpoint(), updates));
+        return new JSONObject(request(getBaseEndpoint(), HttpMethod.PUT, updates).body().string());
     }
 
     @Override
diff --git a/src/main/java/com/saucelabs/saucerest/api/Platform.java b/src/main/java/com/saucelabs/saucerest/api/Platform.java
index 8059f41f..443b3efa 100644
--- a/src/main/java/com/saucelabs/saucerest/api/Platform.java
+++ b/src/main/java/com/saucelabs/saucerest/api/Platform.java
@@ -35,7 +35,7 @@ public Platform(String username, String accessKey, String apiServer) {
     public TestStatus getTestStatus() throws IOException {
         String url = getBaseEndpoint() + "/status";
 
-        return getResponseClass(getResponseObject(url), TestStatus.class);
+        return deserializeJSONObject(getResponseObject(url), TestStatus.class);
     }
 
     /**
@@ -49,7 +49,7 @@ public TestStatus getTestStatus() throws IOException {
     public SupportedPlatforms getSupportedPlatforms(String automationApi) throws IOException {
         String url = getBaseEndpoint() + "/platforms/" + automationApi;
 
-        return new SupportedPlatforms(getResponseListClass(getResponseObject(url), com.saucelabs.saucerest.model.platform.Platform.class));
+        return new SupportedPlatforms(deserializeJSONArray(getResponseObject(url), com.saucelabs.saucerest.model.platform.Platform.class));
     }
 
     /**
diff --git a/src/main/java/com/saucelabs/saucerest/api/RealDevices.java b/src/main/java/com/saucelabs/saucerest/api/RealDevices.java
index 417037b8..d06f0751 100644
--- a/src/main/java/com/saucelabs/saucerest/api/RealDevices.java
+++ b/src/main/java/com/saucelabs/saucerest/api/RealDevices.java
@@ -2,6 +2,7 @@
 
 import com.google.common.collect.ImmutableMap;
 import com.saucelabs.saucerest.DataCenter;
+import com.saucelabs.saucerest.HttpMethod;
 import com.saucelabs.saucerest.model.realdevices.*;
 
 import java.io.IOException;
@@ -33,7 +34,7 @@ public RealDevices(String username, String accessKey, String apiServer) {
     public Devices getDevices() throws IOException {
         String url = getBaseEndpoint() + "/devices";
 
-        return new Devices(getResponseListClass(getResponseObject(url), Device.class));
+        return new Devices(deserializeJSONArray(getResponseObject(url), Device.class));
     }
 
     /**
@@ -46,7 +47,7 @@ public Devices getDevices() throws IOException {
     public Device getSpecificDevice(String deviceID) throws IOException {
         String url = getBaseEndpoint() + "/devices/" + deviceID;
 
-        return getResponseClass(getResponseObject(url), Device.class);
+        return deserializeJSONObject(getResponseObject(url), Device.class);
     }
 
     /**
@@ -59,7 +60,7 @@ public Device getSpecificDevice(String deviceID) throws IOException {
     public AvailableDevices getAvailableDevices() throws IOException {
         String url = getBaseEndpoint() + "/devices/available";
 
-        return new AvailableDevices(getResponseListClass(getResponseObject(url), String.class));
+        return new AvailableDevices(deserializeJSONArray(getResponseObject(url), String.class));
     }
 
     /**
@@ -72,7 +73,7 @@ public AvailableDevices getAvailableDevices() throws IOException {
     public DeviceJobs getDeviceJobs() throws IOException {
         String url = getBaseEndpoint() + "/jobs";
 
-        return getResponseClass(getResponseObject(url), DeviceJobs.class);
+        return deserializeJSONObject(getResponseObject(url), DeviceJobs.class);
     }
 
     /**
@@ -87,7 +88,7 @@ public DeviceJobs getDeviceJobs() throws IOException {
     public DeviceJobs getDeviceJobs(ImmutableMap<String, Object> params) throws IOException {
         String url = getBaseEndpoint() + "/jobs";
 
-        return getResponseClass(getResponseObject(url, params), DeviceJobs.class);
+        return deserializeJSONObject(getResponseObject(url, params).body().string(), DeviceJobs.class);
     }
 
     /**
@@ -102,7 +103,7 @@ public DeviceJobs getDeviceJobs(ImmutableMap<String, Object> params) throws IOEx
     public DeviceJob getSpecificDeviceJob(String jobID) throws IOException {
         String url = getBaseEndpoint() + "/jobs/" + jobID;
 
-        return getResponseClass(getResponseObject(url), DeviceJob.class);
+        return deserializeJSONObject(getResponseObject(url), DeviceJob.class);
     }
 
     /**
@@ -118,12 +119,24 @@ public void deleteSpecificRealDeviceJob(String jobID) {
         String url = getBaseEndpoint() + "/jobs/" + jobID;
 
         try {
-            deleteResponse(url);
+            request(url, HttpMethod.DELETE);
         } catch (Exception e) {
             // do nothing
         }
     }
 
+    /**
+     * Returns details about the current in-use real devices along with the maximum allowed values.
+     *
+     * @return {@link Concurrency}
+     * @throws IOException
+     */
+    public Concurrency getConcurrency() throws IOException {
+        String url = getBaseEndpoint() + "/concurrency";
+
+        return deserializeJSONObject(request(url, HttpMethod.GET).body().string(), Concurrency.class);
+    }
+
     /**
      * The base endpoint of the Platform endpoint APIs.
      */
diff --git a/src/main/java/com/saucelabs/saucerest/api/ResponseHandler.java b/src/main/java/com/saucelabs/saucerest/api/ResponseHandler.java
index 9353675d..88fe842d 100644
--- a/src/main/java/com/saucelabs/saucerest/api/ResponseHandler.java
+++ b/src/main/java/com/saucelabs/saucerest/api/ResponseHandler.java
@@ -20,9 +20,12 @@ public static void responseHandler(AbstractEndpoint endpoint, Response response)
             case HTTP_NOT_FOUND:
                 if (endpoint instanceof SauceConnect) {
                     if (response.request().method().equals(HttpMethod.DELETE.label)) {
-                        String tunnelID = response.request().url().pathSegments().get(response.request().url().pathSegments().size() - 1);
+                        String tunnelID = getID(response);
                         throw new SauceException.NotFound(String.join(System.lineSeparator(), ErrorExplainers.TunnelNotFound(tunnelID)));
                     }
+                } else if (endpoint instanceof Storage) {
+                    String appFileID = getID(response);
+                    throw new SauceException.NotFound(String.join(System.lineSeparator(), ErrorExplainers.AppNotFound(appFileID)));
                 } else {
                     throw new SauceException.NotFound();
                 }
@@ -41,6 +44,28 @@ public static void responseHandler(AbstractEndpoint endpoint, Response response)
         }
     }
 
+    /**
+     * Returns the ID of the resource from the URL.
+     */
+    private static String getID(Response response) {
+        String ID = getLastPathSegment(response, 1);
+
+        // if ID is not a UUID
+        if (!ID.matches("[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}") || !ID.matches("\\d+")) {
+            return getLastPathSegment(response, 2);
+        }
+
+        return ID;
+    }
+
+    private static String getLastPathSegment(Response response, int offset) {
+        if (offset == 0) {
+            offset = 1;
+        }
+
+        return response.request().url().pathSegments().get(response.request().url().pathSegments().size() - offset);
+    }
+
     private static String checkCredentials(AbstractEndpoint endpoint) {
         String username = endpoint.username;
         String accessKey = endpoint.accessKey;
diff --git a/src/main/java/com/saucelabs/saucerest/api/SauceConnect.java b/src/main/java/com/saucelabs/saucerest/api/SauceConnect.java
index e18a9e76..aab3454e 100644
--- a/src/main/java/com/saucelabs/saucerest/api/SauceConnect.java
+++ b/src/main/java/com/saucelabs/saucerest/api/SauceConnect.java
@@ -1,6 +1,7 @@
 package com.saucelabs.saucerest.api;
 
 import com.saucelabs.saucerest.DataCenter;
+import com.saucelabs.saucerest.HttpMethod;
 import com.saucelabs.saucerest.model.sauceconnect.JobsForATunnel;
 import com.saucelabs.saucerest.model.sauceconnect.StopTunnel;
 import com.saucelabs.saucerest.model.sauceconnect.TunnelInformation;
@@ -45,7 +46,7 @@ public List<String> getTunnelsForAUser() throws IOException {
     public List<String> getTunnelsForAUser(String username) throws IOException {
         String url = getBaseEndpoint() + username + "/tunnels";
 
-        return getResponseListClass(getResponseObject(url), String.class);
+        return deserializeJSONArray(getResponseObject(url), String.class);
     }
 
     /**
@@ -59,7 +60,7 @@ public List<String> getTunnelsForAUser(String username) throws IOException {
     public TunnelInformation getTunnelInformation(String username, String tunnelID) throws IOException {
         String url = getBaseEndpoint() + username + "/tunnels/" + tunnelID;
 
-        return getResponseClass(getResponseObject(url), TunnelInformation.class);
+        return deserializeJSONObject(getResponseObject(url), TunnelInformation.class);
     }
 
     /**
@@ -84,7 +85,7 @@ public TunnelInformation getTunnelInformation(String tunnelID) throws IOExceptio
     public JobsForATunnel getCurrentJobsForATunnel(String username, String tunnelID) throws IOException {
         String url = getBaseEndpoint() + username + "/tunnels/" + tunnelID + "/num_jobs";
 
-        return getResponseClass(getResponseObject(url), JobsForATunnel.class);
+        return deserializeJSONObject(getResponseObject(url), JobsForATunnel.class);
     }
 
     /**
@@ -109,7 +110,7 @@ public JobsForATunnel getCurrentJobsForATunnel(String tunnelID) throws IOExcepti
     public StopTunnel stopTunnel(String username, String tunnelID) throws IOException {
         String url = getBaseEndpoint() + username + "/tunnels/" + tunnelID;
 
-        return getResponseClass(deleteResponse(url), StopTunnel.class);
+        return deserializeJSONObject(request(url, HttpMethod.DELETE).body().string(), StopTunnel.class);
     }
 
     /**
@@ -132,7 +133,7 @@ public StopTunnel stopTunnel(String tunnelID) throws IOException {
     public Versions getLatestVersions() throws IOException {
         String url = getBaseEndpoint() + "public/tunnels/info/versions";
 
-        return getResponseClass(getResponseObject(url), Versions.class);
+        return deserializeJSONObject(getResponseObject(url), Versions.class);
     }
 
     /**
@@ -142,4 +143,4 @@ public Versions getLatestVersions() throws IOException {
     public String getBaseEndpoint() {
         return super.getBaseEndpoint() + "rest/v1/";
     }
-}
+}
\ No newline at end of file
diff --git a/src/main/java/com/saucelabs/saucerest/api/Storage.java b/src/main/java/com/saucelabs/saucerest/api/Storage.java
index 4ef25735..2ff17317 100644
--- a/src/main/java/com/saucelabs/saucerest/api/Storage.java
+++ b/src/main/java/com/saucelabs/saucerest/api/Storage.java
@@ -2,6 +2,7 @@
 
 import com.google.common.collect.ImmutableMap;
 import com.saucelabs.saucerest.DataCenter;
+import com.saucelabs.saucerest.HttpMethod;
 import com.saucelabs.saucerest.model.storage.*;
 import okhttp3.*;
 import org.apache.commons.io.FileUtils;
@@ -40,7 +41,7 @@ public Storage(String username, String accessKey, String apiServer) {
     public GetAppFiles getFiles() throws IOException {
         String url = getBaseEndpoint() + "/files";
 
-        return getResponseClass(getResponseObject(url), GetAppFiles.class);
+        return deserializeJSONObject(getResponseObject(url), GetAppFiles.class);
     }
 
     /**
@@ -55,7 +56,7 @@ public GetAppFiles getFiles() throws IOException {
     public GetAppFiles getFiles(Map<String, Object> params) throws IOException {
         String url = getBaseEndpoint() + "/files";
 
-        return getResponseClass(getResponseObject(url, params), GetAppFiles.class);
+        return deserializeJSONObject(getResponseObject(url, params).body().string(), GetAppFiles.class);
     }
 
     /**
@@ -68,7 +69,7 @@ public GetAppFiles getFiles(Map<String, Object> params) throws IOException {
     public GetAppStorageGroups getGroups() throws IOException {
         String url = getBaseEndpoint() + "/groups";
 
-        return getResponseClass(getResponseObject(url), GetAppStorageGroups.class);
+        return deserializeJSONObject(getResponseObject(url), GetAppStorageGroups.class);
     }
 
     /**
@@ -83,7 +84,7 @@ public GetAppStorageGroups getGroups() throws IOException {
     public GetAppStorageGroups getGroups(Map<String, Object> params) throws IOException {
         String url = getBaseEndpoint() + "/groups";
 
-        return getResponseClass(getResponseObject(url, params), GetAppStorageGroups.class);
+        return deserializeJSONObject(getResponseObject(url, params).body().string(), GetAppStorageGroups.class);
     }
 
     /**
@@ -97,7 +98,7 @@ public GetAppStorageGroups getGroups(Map<String, Object> params) throws IOExcept
     public GetAppStorageGroupSettings getGroupSettings(int groupId) throws IOException {
         String url = getBaseEndpoint() + "/groups/" + groupId + "/settings";
 
-        return getResponseClass(getResponseObject(url), GetAppStorageGroupSettings.class);
+        return deserializeJSONObject(getResponseObject(url), GetAppStorageGroupSettings.class);
     }
 
     /**
@@ -112,13 +113,14 @@ public GetAppStorageGroupSettings getGroupSettings(int groupId) throws IOExcepti
     public EditAppGroupSettings updateAppStorageGroupSettings(int groupId, String jsonBody) throws IOException {
         String url = getBaseEndpoint() + "/groups/" + groupId + "/settings";
 
-        return getResponseClass(putResponse(url, jsonBody), EditAppGroupSettings.class);
+        return deserializeJSONObject(request(url, HttpMethod.PUT, jsonBody).body().string(), EditAppGroupSettings.class);
     }
 
     public EditAppGroupSettings updateAppStorageGroupSettings(int groupId, EditAppGroupSettings editAppGroupSettings) throws IOException {
         String url = getBaseEndpoint() + "/groups/" + groupId + "/settings";
 
-        return getResponseClass(putResponse(url, editAppGroupSettings.toJson()), EditAppGroupSettings.class);
+        return deserializeJSONObject(request(url, HttpMethod.PUT, editAppGroupSettings.toJson()).body().string(), EditAppGroupSettings.class);
+
     }
 
     /**
@@ -159,7 +161,7 @@ public UploadFileApp uploadFile(File file, String fileName) throws IOException {
     public UploadFileApp uploadFile(File file, String fileName, String description) throws IOException {
         String url = getBaseEndpoint() + "/upload";
 
-        return getResponseClass(postMultipartResponse(url, file, fileName, description), UploadFileApp.class);
+        return deserializeJSONObject(postMultipartResponse(url, file, fileName, description), UploadFileApp.class);
     }
 
     /**
@@ -192,7 +194,7 @@ public EditFileDescription updateFileDescription(String fileId, String descripti
 
         JSONObject json = new JSONObject(ImmutableMap.of("item", ImmutableMap.of("description", description)));
 
-        return getResponseClass(putResponse(url, json.toString()), EditFileDescription.class);
+        return deserializeJSONObject(request(url, HttpMethod.PUT, json.toString()).body().string(), EditFileDescription.class);
     }
 
     /**
@@ -206,7 +208,7 @@ public EditFileDescription updateFileDescription(String fileId, String descripti
     public DeleteAppFile deleteFile(String fileId) throws IOException {
         String url = getBaseEndpoint() + "/files/" + fileId;
 
-        return getResponseClass(deleteResponse(url), DeleteAppFile.class);
+        return deserializeJSONObject(request(url, HttpMethod.DELETE).body().string(), DeleteAppFile.class);
     }
 
     /**
@@ -220,7 +222,7 @@ public DeleteAppFile deleteFile(String fileId) throws IOException {
     public DeleteAppGroupFiles deleteFileGroup(int groupId) throws IOException {
         String url = getBaseEndpoint() + "/groups/" + groupId;
 
-        return getResponseClass(deleteResponse(url), DeleteAppGroupFiles.class);
+        return deserializeJSONObject(request(url, HttpMethod.DELETE).body().string(), DeleteAppGroupFiles.class);
     }
 
     /**
@@ -281,4 +283,4 @@ private Response getResponse(String url) throws IOException {
 
         return makeRequest(request);
     }
-}
+}
\ No newline at end of file
diff --git a/src/main/java/com/saucelabs/saucerest/model/accounts/Allowed.java b/src/main/java/com/saucelabs/saucerest/model/accounts/Allowed.java
new file mode 100644
index 00000000..9dd56bc9
--- /dev/null
+++ b/src/main/java/com/saucelabs/saucerest/model/accounts/Allowed.java
@@ -0,0 +1,32 @@
+package com.saucelabs.saucerest.model.accounts;
+
+import com.squareup.moshi.Json;
+
+public class Allowed {
+
+    @Json(name = "vms")
+    public Integer vms;
+    @Json(name = "rds")
+    public Integer rds;
+    @Json(name = "mac_vms")
+    public Integer macVms;
+
+    /**
+     * No args constructor for use in serialization
+     */
+    public Allowed() {
+    }
+
+    /**
+     * @param rds
+     * @param macVms
+     * @param vms
+     */
+    public Allowed(Integer vms, Integer rds, Integer macVms) {
+        super();
+        this.vms = vms;
+        this.rds = rds;
+        this.macVms = macVms;
+    }
+
+}
\ No newline at end of file
diff --git a/src/main/java/com/saucelabs/saucerest/model/accounts/Concurrency.java b/src/main/java/com/saucelabs/saucerest/model/accounts/Concurrency.java
new file mode 100644
index 00000000..69703c28
--- /dev/null
+++ b/src/main/java/com/saucelabs/saucerest/model/accounts/Concurrency.java
@@ -0,0 +1,27 @@
+package com.saucelabs.saucerest.model.accounts;
+
+import com.squareup.moshi.Json;
+
+public class Concurrency {
+
+    @Json(name = "organization")
+    public Organization organization;
+    @Json(name = "team")
+    public Team team;
+
+    /**
+     * No args constructor for use in serialization
+     */
+    public Concurrency() {
+    }
+
+    /**
+     * @param organization
+     * @param team
+     */
+    public Concurrency(Organization organization, Team team) {
+        super();
+        this.organization = organization;
+        this.team = team;
+    }
+}
\ No newline at end of file
diff --git a/src/main/java/com/saucelabs/saucerest/model/accounts/CreateUser.java b/src/main/java/com/saucelabs/saucerest/model/accounts/CreateUser.java
new file mode 100644
index 00000000..fff029ad
--- /dev/null
+++ b/src/main/java/com/saucelabs/saucerest/model/accounts/CreateUser.java
@@ -0,0 +1,163 @@
+package com.saucelabs.saucerest.model.accounts;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class CreateUser {
+    public String firstName;
+    public String lastName;
+    public String email;
+    public String userName;
+    public String password;
+    public String organization;
+    public Integer role;
+    public String team;
+
+    private CreateUser(Builder builder) {
+        firstName = builder.firstName;
+        lastName = builder.lastName;
+        email = builder.email;
+        userName = builder.userName;
+        password = builder.password;
+        organization = builder.organization;
+        role = builder.role;
+        team = builder.team;
+    }
+
+    public Map<String, Object> toMap() {
+        Map<String, Object> parameters = new HashMap<>();
+
+        if (this.firstName != null) {
+            parameters.put("first_name", this.firstName);
+        }
+
+        if (this.lastName != null) {
+            parameters.put("last_name", this.lastName);
+        }
+
+        if (this.email != null) {
+            parameters.put("email", this.email);
+        }
+
+        if (this.userName != null) {
+            parameters.put("username", this.userName);
+        }
+
+        if (this.password != null) {
+            parameters.put("password", this.password);
+        }
+
+        if (this.organization != null) {
+            parameters.put("organization", this.organization);
+        }
+
+        if (this.role != null) {
+            parameters.put("role", this.role);
+        }
+
+        if (this.team != null) {
+            parameters.put("team", this.team);
+        }
+
+        return parameters;
+    }
+
+    public static final class Builder {
+        private String firstName;
+        private String lastName;
+        private String email;
+        private String userName;
+        private String password;
+        private String organization;
+        private Integer role;
+        private String team;
+
+        public Builder() {
+        }
+
+        public Builder setFirstName(String val) {
+            firstName = val;
+            return this;
+        }
+
+        public Builder setLastName(String val) {
+            lastName = val;
+            return this;
+        }
+
+        public Builder setEmail(String val) {
+            email = val;
+            return this;
+        }
+
+        public Builder setUserName(String val) {
+            userName = val;
+            return this;
+        }
+
+        public Builder setPassword(String val) {
+            password = val;
+            return this;
+        }
+
+        public Builder setOrganization(String val) {
+            organization = val;
+            return this;
+        }
+
+        public Builder setRole(Roles val) {
+            role = val.getValue();
+            return this;
+        }
+
+        public Builder setTeam(String val) {
+            team = val;
+            return this;
+        }
+
+        public CreateUser build() {
+            checkParameter();
+
+            return new CreateUser(this);
+        }
+
+        /**
+         * Based on <a href="https://docs.saucelabs.com/dev/api/accounts/#create-a-new-user">here</a>
+         */
+        private void checkParameter() {
+            if (firstName == null || firstName.isEmpty())
+                throw new IllegalArgumentException("First name is required");
+
+            if (lastName == null || lastName.isEmpty())
+                throw new IllegalArgumentException("Last name is required");
+
+            if (email == null || email.isEmpty())
+                throw new IllegalArgumentException("Email is required");
+
+            if (userName == null || userName.isEmpty())
+                throw new IllegalArgumentException("Username is required");
+
+            if (password == null || password.isEmpty()) {
+                throw new IllegalArgumentException("Password is required");
+            } else if (password.length() <= 8) {
+                throw new IllegalArgumentException("Password must be at least 8 characters");
+            } else if (!password.matches(".*[0-9].*")) {
+                throw new IllegalArgumentException("Password must contain at least one number");
+            } else if (!password.matches(".*[A-Z].*")) {
+                throw new IllegalArgumentException("Password must contain at least one uppercase letter");
+            } else if (!password.matches(".*[a-z].*")) {
+                throw new IllegalArgumentException("Password must contain at least one lowercase letter");
+            } else if (!password.matches(".*[!@#$%^&*()_+\\-=\\[\\]{};':\"\\\\|,.<>\\/?].*")) {
+                throw new IllegalArgumentException("Password must contain at least one special character");
+            } else if (password.matches(".*\\s.*")) {
+                throw new IllegalArgumentException("Password must not contain any whitespace");
+            }
+
+            if (organization == null || organization.isEmpty())
+                throw new IllegalArgumentException("Organization is required");
+
+            if (role == null)
+                throw new IllegalArgumentException("Role is required");
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/main/java/com/saucelabs/saucerest/model/accounts/Current.java b/src/main/java/com/saucelabs/saucerest/model/accounts/Current.java
new file mode 100644
index 00000000..50f6d306
--- /dev/null
+++ b/src/main/java/com/saucelabs/saucerest/model/accounts/Current.java
@@ -0,0 +1,31 @@
+package com.saucelabs.saucerest.model.accounts;
+
+import com.squareup.moshi.Json;
+
+public class Current {
+
+    @Json(name = "vms")
+    public Integer vms;
+    @Json(name = "rds")
+    public Integer rds;
+    @Json(name = "mac_vms")
+    public Integer macVms;
+
+    /**
+     * No args constructor for use in serialization
+     */
+    public Current() {
+    }
+
+    /**
+     * @param rds
+     * @param macVms
+     * @param vms
+     */
+    public Current(Integer vms, Integer rds, Integer macVms) {
+        super();
+        this.vms = vms;
+        this.rds = rds;
+        this.macVms = macVms;
+    }
+}
\ No newline at end of file
diff --git a/src/main/java/com/saucelabs/saucerest/model/accounts/LookupUsersParameter.java b/src/main/java/com/saucelabs/saucerest/model/accounts/LookupUsersParameter.java
index 43595130..4f368ef3 100644
--- a/src/main/java/com/saucelabs/saucerest/model/accounts/LookupUsersParameter.java
+++ b/src/main/java/com/saucelabs/saucerest/model/accounts/LookupUsersParameter.java
@@ -13,22 +13,6 @@ public class LookupUsersParameter {
     private final Integer limit;
     private final Integer offset;
 
-    public enum Roles {
-        ORGADMIN(1),
-        TEAMADMIN(4),
-        MEMBER(3);
-
-        private final int value;
-
-        Roles(int value) {
-            this.value = value;
-        }
-
-        public int getValue() {
-            return value;
-        }
-    }
-
     public enum Status {
         ACTIVE("active"),
         PENDING("pending"),
@@ -142,7 +126,7 @@ public Builder setTeamName(String val) {
         }
 
         public Builder setRoles(Roles val) {
-            roles = val.value;
+            roles = val.getValue();
             return this;
         }
 
diff --git a/src/main/java/com/saucelabs/saucerest/model/accounts/Organization.java b/src/main/java/com/saucelabs/saucerest/model/accounts/Organization.java
index e00edace..0c3ff4d0 100644
--- a/src/main/java/com/saucelabs/saucerest/model/accounts/Organization.java
+++ b/src/main/java/com/saucelabs/saucerest/model/accounts/Organization.java
@@ -16,6 +16,10 @@ public class Organization {
     public String createdAt;
     @Json(name = "updated_at")
     public String updatedAt;
+    @Json(name = "current")
+    public Current current;
+    @Json(name = "allowed")
+    public Allowed allowed;
 
     /**
      * No args constructor for use in serialization
@@ -23,7 +27,7 @@ public class Organization {
     public Organization() {
     }
 
-    public Organization(String id, Settings settings, Integer totalVmConcurrency, String name, String createdAt, String updatedAt) {
+    public Organization(String id, Settings settings, Integer totalVmConcurrency, String name, String createdAt, String updatedAt, Current current, Allowed allowed) {
         super();
         this.id = id;
         this.settings = settings;
@@ -31,5 +35,7 @@ public Organization(String id, Settings settings, Integer totalVmConcurrency, St
         this.name = name;
         this.createdAt = createdAt;
         this.updatedAt = updatedAt;
+        this.current = current;
+        this.allowed = allowed;
     }
 }
\ No newline at end of file
diff --git a/src/main/java/com/saucelabs/saucerest/model/accounts/Roles.java b/src/main/java/com/saucelabs/saucerest/model/accounts/Roles.java
new file mode 100644
index 00000000..b6682c4b
--- /dev/null
+++ b/src/main/java/com/saucelabs/saucerest/model/accounts/Roles.java
@@ -0,0 +1,17 @@
+package com.saucelabs.saucerest.model.accounts;
+
+public enum Roles {
+    ORGADMIN(1),
+    TEAMADMIN(4),
+    MEMBER(3);
+
+    private final int value;
+
+    Roles(int value) {
+        this.value = value;
+    }
+
+    public int getValue() {
+        return value;
+    }
+}
\ No newline at end of file
diff --git a/src/main/java/com/saucelabs/saucerest/model/accounts/SetTeam.java b/src/main/java/com/saucelabs/saucerest/model/accounts/SetTeam.java
new file mode 100644
index 00000000..65157816
--- /dev/null
+++ b/src/main/java/com/saucelabs/saucerest/model/accounts/SetTeam.java
@@ -0,0 +1,31 @@
+package com.saucelabs.saucerest.model.accounts;
+
+import com.squareup.moshi.Json;
+
+public class SetTeam {
+
+    @Json(name = "id")
+    public String id;
+    @Json(name = "user")
+    public User user;
+    @Json(name = "team")
+    public Team team;
+    @Json(name = "created_at")
+    public String createdAt;
+    @Json(name = "updated_at")
+    public String updatedAt;
+
+    public SetTeam(String id, User user, Team team, String createdAt, String updatedAt) {
+        this.id = id;
+        this.user = user;
+        this.team = team;
+        this.createdAt = createdAt;
+        this.updatedAt = updatedAt;
+    }
+
+    /**
+     * No args constructor for use in serialization
+     */
+    public SetTeam() {
+    }
+}
\ No newline at end of file
diff --git a/src/main/java/com/saucelabs/saucerest/model/accounts/Team.java b/src/main/java/com/saucelabs/saucerest/model/accounts/Team.java
index 6f398c60..bcb20353 100644
--- a/src/main/java/com/saucelabs/saucerest/model/accounts/Team.java
+++ b/src/main/java/com/saucelabs/saucerest/model/accounts/Team.java
@@ -22,6 +22,10 @@ public class Team {
     public String orgUuid;
     @Json(name = "updated_at")
     public String updatedAt;
+    @Json(name = "current")
+    public Current current;
+    @Json(name = "allowed")
+    public Allowed allowed;
 
     /**
      * No args constructor for use in serialization
@@ -40,7 +44,7 @@ public Team() {
      * @param orgUuid
      * @param updatedAt
      */
-    public Team(String id, Settings settings, String createdAt, String description, Group group, Boolean isDefault, String name, String orgUuid, String updatedAt) {
+    public Team(String id, Settings settings, String createdAt, String description, Group group, Boolean isDefault, String name, String orgUuid, String updatedAt, Current current, Allowed allowed) {
         super();
         this.id = id;
         this.settings = settings;
@@ -51,5 +55,7 @@ public Team(String id, Settings settings, String createdAt, String description,
         this.name = name;
         this.orgUuid = orgUuid;
         this.updatedAt = updatedAt;
+        this.current = current;
+        this.allowed = allowed;
     }
 }
\ No newline at end of file
diff --git a/src/main/java/com/saucelabs/saucerest/model/accounts/UpdateUser.java b/src/main/java/com/saucelabs/saucerest/model/accounts/UpdateUser.java
new file mode 100644
index 00000000..5a5cb6ac
--- /dev/null
+++ b/src/main/java/com/saucelabs/saucerest/model/accounts/UpdateUser.java
@@ -0,0 +1,76 @@
+package com.saucelabs.saucerest.model.accounts;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class UpdateUser {
+    public String userID;
+    public String firstName;
+    public String lastName;
+    public String phone;
+
+    private UpdateUser(Builder builder) {
+        userID = builder.userID;
+        firstName = builder.firstName;
+        lastName = builder.lastName;
+        phone = builder.phone;
+    }
+
+    public Map<String, Object> toMap() {
+        Map<String, Object> parameters = new HashMap<>();
+
+        if (this.firstName != null) {
+            parameters.put("first_name", this.firstName);
+        }
+
+        if (this.lastName != null) {
+            parameters.put("last_name", this.lastName);
+        }
+
+        if (this.phone != null) {
+            parameters.put("phone", this.phone);
+        }
+
+        return parameters;
+    }
+
+    public static final class Builder {
+        private String userID;
+        private String firstName;
+        private String lastName;
+        private String phone;
+
+        public Builder() {
+        }
+
+        public Builder setUserID(String val) {
+            userID = val;
+            return this;
+        }
+
+        public Builder setFirstName(String val) {
+            firstName = val;
+            return this;
+        }
+
+        public Builder setLastName(String val) {
+            lastName = val;
+            return this;
+        }
+
+        public Builder setPhone(String val) {
+            phone = val;
+            return this;
+        }
+
+        public UpdateUser build() {
+            if (phone != null) {
+                if (!phone.matches("^\\+?1?\\d{8,15}$")) {
+                    throw new IllegalArgumentException("Phone number must be in international format, e.g. +1 1234567890");
+                }
+            }
+
+            return new UpdateUser(this);
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/main/java/com/saucelabs/saucerest/model/accounts/User.java b/src/main/java/com/saucelabs/saucerest/model/accounts/User.java
index 4fcc92a5..9819e0e0 100644
--- a/src/main/java/com/saucelabs/saucerest/model/accounts/User.java
+++ b/src/main/java/com/saucelabs/saucerest/model/accounts/User.java
@@ -42,6 +42,8 @@ public class User {
     public String updatedAt;
     @Json(name = "user_type")
     public String userType;
+    @Json(name = "access_key")
+    public String accessKey;
 
     /**
      * No args constructor for use in serialization
@@ -49,7 +51,7 @@ public class User {
     public User() {
     }
 
-    public User(String id, String email, String firstName, String lastName, String username, String createdAt, List<Group> groups, Boolean isActive, Boolean isOrganizationAdmin, Boolean isTeamAdmin, Boolean isStaff, Boolean isSuperuser, Organization organization, String phone, List<Role> roles, List<Team> teams, String updatedAt, String userType) {
+    public User(String id, String email, String firstName, String lastName, String username, String createdAt, List<Group> groups, Boolean isActive, Boolean isOrganizationAdmin, Boolean isTeamAdmin, Boolean isStaff, Boolean isSuperuser, Organization organization, String phone, List<Role> roles, List<Team> teams, String updatedAt, String userType, String accessKey) {
         super();
         this.id = id;
         this.email = email;
@@ -69,5 +71,6 @@ public User(String id, String email, String firstName, String lastName, String u
         this.teams = teams;
         this.updatedAt = updatedAt;
         this.userType = userType;
+        this.accessKey = accessKey;
     }
 }
\ No newline at end of file
diff --git a/src/main/java/com/saucelabs/saucerest/model/accounts/UserConcurrency.java b/src/main/java/com/saucelabs/saucerest/model/accounts/UserConcurrency.java
new file mode 100644
index 00000000..1c62c2d5
--- /dev/null
+++ b/src/main/java/com/saucelabs/saucerest/model/accounts/UserConcurrency.java
@@ -0,0 +1,27 @@
+package com.saucelabs.saucerest.model.accounts;
+
+import com.squareup.moshi.Json;
+
+public class UserConcurrency {
+
+    @Json(name = "timestamp")
+    public Float timestamp;
+    @Json(name = "concurrency")
+    public Concurrency concurrency;
+
+    /**
+     * No args constructor for use in serialization
+     */
+    public UserConcurrency() {
+    }
+
+    /**
+     * @param timestamp
+     * @param concurrency
+     */
+    public UserConcurrency(Float timestamp, Concurrency concurrency) {
+        super();
+        this.timestamp = timestamp;
+        this.concurrency = concurrency;
+    }
+}
\ No newline at end of file
diff --git a/src/main/java/com/saucelabs/saucerest/model/accounts/UsersTeam.java b/src/main/java/com/saucelabs/saucerest/model/accounts/UsersTeam.java
new file mode 100644
index 00000000..7dc8b4e8
--- /dev/null
+++ b/src/main/java/com/saucelabs/saucerest/model/accounts/UsersTeam.java
@@ -0,0 +1,33 @@
+package com.saucelabs.saucerest.model.accounts;
+
+import com.squareup.moshi.Json;
+
+import java.util.List;
+
+public class UsersTeam {
+
+    @Json(name = "links")
+    public Links links;
+    @Json(name = "count")
+    public Integer count;
+    @Json(name = "results")
+    public List<Result> results;
+
+    /**
+     * No args constructor for use in serialization
+     */
+    public UsersTeam() {
+    }
+
+    /**
+     * @param count
+     * @param links
+     * @param results
+     */
+    public UsersTeam(Links links, Integer count, List<Result> results) {
+        super();
+        this.links = links;
+        this.count = count;
+        this.results = results;
+    }
+}
\ No newline at end of file
diff --git a/src/main/java/com/saucelabs/saucerest/model/realdevices/Concurrency.java b/src/main/java/com/saucelabs/saucerest/model/realdevices/Concurrency.java
new file mode 100644
index 00000000..ac832107
--- /dev/null
+++ b/src/main/java/com/saucelabs/saucerest/model/realdevices/Concurrency.java
@@ -0,0 +1,23 @@
+package com.saucelabs.saucerest.model.realdevices;
+
+import com.squareup.moshi.Json;
+
+public class Concurrency {
+
+    @Json(name = "organization")
+    public Organization organization;
+
+    /**
+     * No args constructor for use in serialization
+     */
+    public Concurrency() {
+    }
+
+    /**
+     * @param organization
+     */
+    public Concurrency(Organization organization) {
+        super();
+        this.organization = organization;
+    }
+}
\ No newline at end of file
diff --git a/src/main/java/com/saucelabs/saucerest/model/realdevices/DeviceJob.java b/src/main/java/com/saucelabs/saucerest/model/realdevices/DeviceJob.java
index 8250d815..957a7e5b 100644
--- a/src/main/java/com/saucelabs/saucerest/model/realdevices/DeviceJob.java
+++ b/src/main/java/com/saucelabs/saucerest/model/realdevices/DeviceJob.java
@@ -90,11 +90,13 @@ public class DeviceJob {
     public String testReportType;
     @Json(name = "crash_log_url")
     public String crashLogUrl;
+    @Json(name = "used_cached_device")
+    public Boolean usedCachedDevice;
 
     public DeviceJob() {
     }
 
-    public DeviceJob(ApplicationSummary applicationSummary, Object assignedTunnelId, String deviceType, String ownerSauce, String automationBackend, BaseConfig baseConfig, String build, Boolean collectsAutomatorLog, String consolidatedStatus, Long creationTime, DeviceDescriptor deviceDescriptor, Long endTime, Object error, String id, String frameworkLogUrl, String deviceLogUrl, String requestsUrl, Object testCasesUrl, Object junitLogUrl, Boolean manual, Long modificationTime, String name, String os, String osVersion, String deviceName, Boolean passed, Boolean proxied, Boolean recordScreenshots, List<Object> screenshots, Boolean recordVideo, Long startTime, String status, List<Object> tags, String videoUrl, String remoteAppFileUrl, String appiumSessionId, Object deviceSessionId, String client, String networkLogUrl, String testfairyLogUrl, String testReportType, String crashLogUrl) {
+    public DeviceJob(ApplicationSummary applicationSummary, Object assignedTunnelId, String deviceType, String ownerSauce, String automationBackend, BaseConfig baseConfig, String build, Boolean collectsAutomatorLog, String consolidatedStatus, Long creationTime, DeviceDescriptor deviceDescriptor, Long endTime, Object error, String id, String frameworkLogUrl, String deviceLogUrl, String requestsUrl, Object testCasesUrl, Object junitLogUrl, Boolean manual, Long modificationTime, String name, String os, String osVersion, String deviceName, Boolean passed, Boolean proxied, Boolean recordScreenshots, List<Object> screenshots, Boolean recordVideo, Long startTime, String status, List<Object> tags, String videoUrl, String remoteAppFileUrl, String appiumSessionId, Object deviceSessionId, String client, String networkLogUrl, String testfairyLogUrl, String testReportType, String crashLogUrl, Boolean usedCachedDevice) {
         super();
         this.applicationSummary = applicationSummary;
         this.assignedTunnelId = assignedTunnelId;
@@ -138,5 +140,6 @@ public DeviceJob(ApplicationSummary applicationSummary, Object assignedTunnelId,
         this.testfairyLogUrl = testfairyLogUrl;
         this.testReportType = testReportType;
         this.crashLogUrl = crashLogUrl;
+        this.usedCachedDevice = usedCachedDevice;
     }
 }
\ No newline at end of file
diff --git a/src/main/java/com/saucelabs/saucerest/model/realdevices/Organization.java b/src/main/java/com/saucelabs/saucerest/model/realdevices/Organization.java
new file mode 100644
index 00000000..7064a5f5
--- /dev/null
+++ b/src/main/java/com/saucelabs/saucerest/model/realdevices/Organization.java
@@ -0,0 +1,27 @@
+package com.saucelabs.saucerest.model.realdevices;
+
+import com.squareup.moshi.Json;
+
+public class Organization {
+
+    @Json(name = "current")
+    public Integer current;
+    @Json(name = "maximum")
+    public Integer maximum;
+
+    /**
+     * No args constructor for use in serialization
+     */
+    public Organization() {
+    }
+
+    /**
+     * @param current
+     * @param maximum
+     */
+    public Organization(Integer current, Integer maximum) {
+        super();
+        this.current = current;
+        this.maximum = maximum;
+    }
+}
\ No newline at end of file
diff --git a/src/main/java/com/saucelabs/saucerest/model/storage/Settings.java b/src/main/java/com/saucelabs/saucerest/model/storage/Settings.java
index c07d42e0..ced68650 100644
--- a/src/main/java/com/saucelabs/saucerest/model/storage/Settings.java
+++ b/src/main/java/com/saucelabs/saucerest/model/storage/Settings.java
@@ -120,21 +120,4 @@ public Settings build() {
             return new Settings(this);
         }
     }
-
-//    public Settings() {
-//    }
-//
-//    public Settings(Proxy proxy, Boolean audioCapture, Boolean proxyEnabled, String lang, String orientation, Boolean resigningEnabled, Resigning resigning, Instrumentation instrumentation, Boolean setupDeviceLock, Boolean instrumentationEnabled) {
-//        super();
-//        this.proxy = proxy;
-//        this.audioCapture = audioCapture;
-//        this.proxyEnabled = proxyEnabled;
-//        this.lang = lang;
-//        this.orientation = orientation;
-//        this.resigningEnabled = resigningEnabled;
-//        this.resigning = resigning;
-//        this.instrumentation = instrumentation;
-//        this.setupDeviceLock = setupDeviceLock;
-//        this.instrumentationEnabled = instrumentationEnabled;
-//    }
 }
\ No newline at end of file
diff --git a/src/test/java/com/saucelabs/saucerest/integration/AccountsTest.java b/src/test/java/com/saucelabs/saucerest/integration/AccountsTest.java
index b2720300..2a1296f7 100644
--- a/src/test/java/com/saucelabs/saucerest/integration/AccountsTest.java
+++ b/src/test/java/com/saucelabs/saucerest/integration/AccountsTest.java
@@ -5,12 +5,16 @@
 import com.saucelabs.saucerest.SauceREST;
 import com.saucelabs.saucerest.api.Accounts;
 import com.saucelabs.saucerest.model.accounts.*;
+import com.saucelabs.saucerest.model.realdevices.Concurrency;
 import org.apache.commons.lang3.RandomStringUtils;
+import org.junit.jupiter.api.Disabled;
 import org.junit.jupiter.params.ParameterizedTest;
 import org.junit.jupiter.params.provider.EnumSource;
 
 import java.io.IOException;
 import java.util.List;
+import java.util.Random;
+import java.util.stream.Collectors;
 
 import static org.junit.jupiter.api.Assertions.*;
 
@@ -91,7 +95,7 @@ public void createTeamTest(DataCenter dataCenter) throws IOException {
         assertNotNull(createTeam);
         assertEquals(teamName, createTeam.name);
 
-        accounts.deleteTeam(createTeam.id);
+        assertEquals(204, accounts.deleteTeam(createTeam.id).code());
     }
 
     @ParameterizedTest
@@ -115,7 +119,7 @@ public void updateTeamTest(DataCenter dataCenter) throws IOException {
         assertEquals("Updated description", updateTeam.description);
         assertEquals("Updated" + teamName, updateTeam.name);
         assertEquals(0, updateTeam.settings.virtualMachines);
-        accounts.deleteTeam(createTeam.id);
+        assertEquals(204, accounts.deleteTeam(createTeam.id).code());
     }
 
     @ParameterizedTest
@@ -141,7 +145,7 @@ public void partiallyUpdateTeamTest(DataCenter dataCenter) throws IOException {
         UpdateTeam updateTeam = accounts.partiallyUpdateTeam(createTeam.id, partiallyUpdateTeam);
 
         assertEquals("Updated" + teamName, updateTeam.name);
-        accounts.deleteTeam(createTeam.id);
+        assertEquals(204, accounts.deleteTeam(createTeam.id).code());
     }
 
     @ParameterizedTest
@@ -178,7 +182,7 @@ public void lookupUsersWithParametersTest(DataCenter dataCenter) throws IOExcept
         Accounts accounts = sauceREST.getAccounts();
 
         LookupUsersParameter lookupUsersParameter = new LookupUsersParameter.Builder()
-            .setRoles(LookupUsersParameter.Roles.ORGADMIN)
+            .setRoles(Roles.ORGADMIN)
             .build();
 
         LookupUsers lookupUsers = accounts.lookupUsers(lookupUsersParameter);
@@ -197,4 +201,249 @@ public void getUserTest(DataCenter dataCenter) throws IOException {
 
         assertNotNull(user);
     }
+
+    @ParameterizedTest
+    @EnumSource(value = DataCenter.class, names = {"US_EAST"}, mode = EnumSource.Mode.EXCLUDE)
+    public void createUserTest(DataCenter dataCenter) throws IOException {
+        SauceREST sauceREST = new SauceREST(dataCenter);
+        Accounts accounts = sauceREST.getAccounts();
+
+        User user = createTestUser(accounts);
+
+        assertNotNull(user);
+        assertTrue(user.id.length() > 0);
+    }
+
+    private static User createTestUser(Accounts accounts) throws IOException {
+        CreateUser createUser = new CreateUser.Builder()
+            .setEmail(RandomStringUtils.randomAlphabetic(8) + "@example.com")
+            .setFirstName(RandomStringUtils.randomAlphabetic(8))
+            .setLastName(RandomStringUtils.randomAlphabetic(8))
+            .setPassword(RandomStringUtils.randomNumeric(4) + RandomStringUtils.randomAlphabetic(4) + "!$%" + "Aa")
+            .setOrganization(accounts.getOrganization().results.get(0).id)
+            .setRole(Roles.MEMBER)
+            .setUserName("saucerest-java-integration-test-user-" + RandomStringUtils.randomAlphabetic(8))
+            .build();
+
+        User user = accounts.createUser(createUser);
+        return user;
+    }
+
+    @ParameterizedTest
+    @EnumSource(value = DataCenter.class, names = {"US_EAST"}, mode = EnumSource.Mode.EXCLUDE)
+    public void updateUserTest(DataCenter dataCenter) throws IOException {
+        SauceREST sauceREST = new SauceREST(dataCenter);
+        Accounts accounts = sauceREST.getAccounts();
+
+        LookupUsers lookupUsers = accounts.lookupUsers();
+        User user;
+        Random rand = new Random();
+
+        List<Result> validResults = lookupUsers.results.stream()
+            .filter(r -> r.username.startsWith("saucerest-java-integration-test-user"))
+            .collect(Collectors.toList());
+
+        Result result = validResults.stream()
+            .skip(rand.nextInt(validResults.size()))
+            .findFirst()
+            .get();
+
+        user = accounts.getUser(result.id);
+
+        String timeStamp = String.valueOf(new Random(System.currentTimeMillis()).nextInt()).replace("-", "");
+
+        UpdateUser updateUser = new UpdateUser.Builder()
+            .setUserID(user.id)
+            .setFirstName("Updated " + timeStamp)
+            .setLastName("Updated " + timeStamp)
+            .setPhone("+123456789")
+            .build();
+
+        User updatedUser = accounts.updateUser(updateUser);
+
+        assertEquals("Updated " + timeStamp, updatedUser.firstName);
+        assertEquals("Updated " + timeStamp, updatedUser.lastName);
+        assertEquals("+123456789", updatedUser.phone);
+    }
+
+    @ParameterizedTest
+    @EnumSource(value = DataCenter.class, names = {"US_EAST"}, mode = EnumSource.Mode.EXCLUDE)
+    public void partiallyUpdateUserTest(DataCenter dataCenter) throws IOException {
+        SauceREST sauceREST = new SauceREST(dataCenter);
+        Accounts accounts = sauceREST.getAccounts();
+
+        LookupUsers lookupUsers = accounts.lookupUsers();
+        User user;
+        Random rand = new Random();
+
+        List<Result> validResults = lookupUsers.results.stream()
+            .filter(r -> r.username.startsWith("saucerest-java-integration-test-user"))
+            .collect(Collectors.toList());
+
+        Result result = validResults.stream()
+            .skip(rand.nextInt(validResults.size()))
+            .findFirst()
+            .get();
+
+        user = accounts.getUser(result.id);
+
+        String timeStamp = String.valueOf(new Random(System.currentTimeMillis()).nextInt()).replace("-", "");
+
+        UpdateUser updateUser = new UpdateUser.Builder()
+            .setUserID(user.id)
+            .setFirstName("Updated " + timeStamp)
+            .build();
+
+        User updatedUser = accounts.partiallyUpdateUser(updateUser);
+
+        assertEquals("Updated " + timeStamp, updatedUser.firstName);
+    }
+
+    @ParameterizedTest
+    @EnumSource(value = DataCenter.class, names = {"US_EAST", "APAC_SOUTHEAST"}, mode = EnumSource.Mode.EXCLUDE)
+    public void getUserConcurrencyTest(DataCenter dataCenter) throws IOException {
+        SauceREST sauceREST = new SauceREST(dataCenter);
+        Accounts accounts = sauceREST.getAccounts();
+
+        UserConcurrency userConcurrency = accounts.getUserConcurrency(sauceREST.getUsername());
+        Concurrency realDeviceConcurrency = sauceREST.getRealDevices().getConcurrency();
+
+        assertNotNull(userConcurrency);
+        assertNotNull(realDeviceConcurrency);
+    }
+
+    @ParameterizedTest
+    @EnumSource(value = DataCenter.class, names = {"US_EAST"}, mode = EnumSource.Mode.EXCLUDE)
+    public void getUsersTeamTest(DataCenter dataCenter) throws IOException {
+        SauceREST sauceREST = new SauceREST(dataCenter);
+        Accounts accounts = sauceREST.getAccounts();
+
+        LookupUsersParameter lookupUsersParameter = new LookupUsersParameter.Builder()
+            .setUsername(sauceREST.getUsername())
+            .build();
+
+        LookupUsers lookupUsers = accounts.lookupUsers(lookupUsersParameter);
+
+        UsersTeam usersTeam = accounts.getUsersTeam(lookupUsers.results.get(0).id);
+
+        assertNotNull(usersTeam);
+        // Integration test user is and should not be part of a non-default team
+        assertEquals(0, usersTeam.results.size());
+    }
+
+    @Disabled("Need to find a way to reliably get a user with a team.")
+    @ParameterizedTest
+    @EnumSource(value = DataCenter.class, names = {"US_EAST"}, mode = EnumSource.Mode.EXCLUDE)
+    public void setRoleTest(DataCenter dataCenter) throws IOException {
+        SauceREST sauceREST = new SauceREST(dataCenter);
+        Accounts accounts = sauceREST.getAccounts();
+
+        LookupUsersParameter lookupUsersParameter = new LookupUsersParameter.Builder()
+            .setUsername("saucerest-java-integration-test-user")
+            .setRoles(Roles.MEMBER)
+            .build();
+
+        LookupUsers lookupUsers = accounts.lookupUsers(lookupUsersParameter);
+
+        List<Result> validResults = lookupUsers.results.stream()
+            .filter(r -> r.teams.size() > 0)
+            .collect(Collectors.toList());
+
+        Result result = validResults.stream()
+            .skip(new Random().nextInt(validResults.size()))
+            .findFirst()
+            .get();
+
+        User user = accounts.getUser(result.id);
+        CreateTeam createTeam = accounts.createTeam("001-" + RandomStringUtils.randomAlphabetic(8), 0, "Test team created as part of integration tests");
+
+        // Assign fetched user to newly created team
+        SetTeam setTeam = accounts.setUsersTeam(user.id, createTeam.id);
+        assertEquals(createTeam.id, setTeam.team.id);
+
+        user = accounts.setTeamAdmin(user.id);
+        assertTrue(user.roles.get(0).role.equals(Roles.TEAMADMIN.getValue()));
+
+        user = accounts.setAdmin(user.id);
+        assertTrue(user.roles.get(0).role.equals(Roles.ORGADMIN.getValue()));
+
+        user = accounts.setMember(user.id);
+        assertTrue(user.roles.get(0).role.equals(Roles.MEMBER.getValue()));
+
+        accounts.deleteTeam(createTeam.id);
+
+        assertThrows(SauceException.class, () -> {
+            accounts.getSpecificTeam(createTeam.id);
+        });
+    }
+
+    @ParameterizedTest
+    @EnumSource(value = DataCenter.class, names = {"US_EAST"}, mode = EnumSource.Mode.EXCLUDE)
+    public void deactivateUserTest(DataCenter dataCenter) throws IOException {
+        SauceREST sauceREST = new SauceREST(dataCenter);
+        Accounts accounts = sauceREST.getAccounts();
+
+        User user = createTestUser(accounts);
+
+        if (user.id != null) {
+            assertTrue(user.isActive);
+            User deactivatedUser = accounts.deactivateUser(user.id);
+            assertFalse(deactivatedUser.isActive);
+        } else {
+            fail("Test user was not created");
+        }
+    }
+
+    @ParameterizedTest
+    @EnumSource(value = DataCenter.class, names = {"US_EAST"}, mode = EnumSource.Mode.EXCLUDE)
+    public void activateUserTest(DataCenter dataCenter) throws IOException {
+        SauceREST sauceREST = new SauceREST(dataCenter);
+        Accounts accounts = sauceREST.getAccounts();
+
+        User user = createTestUser(accounts);
+
+        if (user.id != null) {
+            assertTrue(user.isActive);
+            User deactivatedUser = accounts.deactivateUser(user.id);
+            assertFalse(deactivatedUser.isActive);
+            User activatedUser = accounts.activateUser(user.id);
+            assertTrue(activatedUser.isActive);
+        } else {
+            fail("Test user was not created");
+        }
+    }
+
+    @ParameterizedTest
+    @EnumSource(value = DataCenter.class, names = {"US_EAST"}, mode = EnumSource.Mode.EXCLUDE)
+    public void resetAccessKeyTest(DataCenter dataCenter) throws IOException {
+        SauceREST sauceREST = new SauceREST(dataCenter);
+        Accounts accounts = sauceREST.getAccounts();
+
+        User user = createTestUser(accounts);
+
+        if (user.id != null) {
+            String oldAccessKey = user.accessKey;
+            List<User> updatedUser = accounts.resetAccessKey(user.id);
+            String newAccessKey = updatedUser.get(0).accessKey;
+            assertNotEquals(oldAccessKey, newAccessKey);
+        } else {
+            fail("Test user was not created");
+        }
+    }
+
+    @ParameterizedTest
+    @EnumSource(value = DataCenter.class, names = {"US_EAST"}, mode = EnumSource.Mode.EXCLUDE)
+    public void getAccessKeyTest(DataCenter dataCenter) throws IOException {
+        SauceREST sauceREST = new SauceREST(dataCenter);
+        Accounts accounts = sauceREST.getAccounts();
+
+        User user = createTestUser(accounts);
+
+        if (user.id != null) {
+            String accessKey = accounts.getAccessKey(user.id).accessKey;
+            assertTrue(accessKey.length() > 0);
+        } else {
+            fail("Test user was not created");
+        }
+    }
 }
\ No newline at end of file
diff --git a/src/test/java/com/saucelabs/saucerest/integration/RealDevicesTest.java b/src/test/java/com/saucelabs/saucerest/integration/RealDevicesTest.java
index 423ff69d..5f293472 100644
--- a/src/test/java/com/saucelabs/saucerest/integration/RealDevicesTest.java
+++ b/src/test/java/com/saucelabs/saucerest/integration/RealDevicesTest.java
@@ -17,17 +17,11 @@
 import java.net.MalformedURLException;
 import java.net.URL;
 
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+
 public class RealDevicesTest {
     private final ThreadLocal<RealDevices> realDevices = new ThreadLocal<>();
 
-    /**
-     * Use this instead of {@link com.saucelabs.saucerest.integration.DataCenter} because not all regions support
-     * app files yet.
-     */
-    enum Region {
-        EU_CENTRAL, US_WEST
-    }
-
     @BeforeAll
     public static void runRealDeviceTest() throws MalformedURLException {
         MutableCapabilities capabilities = new MutableCapabilities();
@@ -62,7 +56,7 @@ public void getDevices(Region region) throws IOException {
 
         Devices devices = realDevices.get().getDevices();
 
-        Assertions.assertNotNull(devices);
+        assertNotNull(devices);
     }
 
     @ParameterizedTest
@@ -74,7 +68,7 @@ public void getSpecificDevice(Region region) throws IOException {
         String deviceId = devices.deviceList.get(0).id;
         Device device = realDevices.get().getSpecificDevice(deviceId);
 
-        Assertions.assertNotNull(device);
+        assertNotNull(device);
     }
 
     @ParameterizedTest
@@ -84,7 +78,7 @@ public void getAvailableDevices(Region region) throws IOException {
 
         AvailableDevices availableDevices = realDevices.get().getAvailableDevices();
 
-        Assertions.assertNotNull(availableDevices);
+        assertNotNull(availableDevices);
     }
 
     @ParameterizedTest
@@ -94,7 +88,7 @@ public void getDeviceJobs(Region region) throws IOException {
 
         DeviceJobs deviceJobs = realDevices.get().getDeviceJobs();
 
-        Assertions.assertNotNull(deviceJobs);
+        assertNotNull(deviceJobs);
     }
 
     @ParameterizedTest
@@ -104,7 +98,7 @@ public void getDeviceJobsWithLimit_5(Region region) throws IOException {
 
         DeviceJobs deviceJobs = realDevices.get().getDeviceJobs(ImmutableMap.of("limit", 5));
 
-        Assertions.assertNotNull(deviceJobs);
+        assertNotNull(deviceJobs);
         Assertions.assertEquals(5, deviceJobs.metaData.limit);
     }
 
@@ -115,7 +109,7 @@ public void getDeviceJobsWithOffset_5(Region region) throws IOException {
 
         DeviceJobs deviceJobs = realDevices.get().getDeviceJobs(ImmutableMap.of("offset", 5));
 
-        Assertions.assertNotNull(deviceJobs);
+        assertNotNull(deviceJobs);
         Assertions.assertEquals(5, deviceJobs.metaData.offset);
     }
 
@@ -126,7 +120,7 @@ public void getDeviceJobsWithLimitAndOffset(Region region) throws IOException {
 
         DeviceJobs deviceJobs = realDevices.get().getDeviceJobs(ImmutableMap.of("offset", 5, "limit", 6));
 
-        Assertions.assertNotNull(deviceJobs);
+        assertNotNull(deviceJobs);
         Assertions.assertEquals(5, deviceJobs.metaData.offset);
         Assertions.assertEquals(6, deviceJobs.metaData.limit);
     }
@@ -139,6 +133,24 @@ public void getSpecificDeviceJob(Region region) throws IOException {
         DeviceJobs deviceJobs = realDevices.get().getDeviceJobs();
         DeviceJob deviceJob = realDevices.get().getSpecificDeviceJob(deviceJobs.entities.get(0).id);
 
-        Assertions.assertNotNull(deviceJob);
+        assertNotNull(deviceJob);
+    }
+
+    @ParameterizedTest
+    @EnumSource(Region.class)
+    public void getConcurrency(Region region) throws IOException {
+        setup(region);
+
+        Concurrency concurrency = realDevices.get().getConcurrency();
+
+        assertNotNull(concurrency);
+    }
+
+    /**
+     * Use this instead of {@link com.saucelabs.saucerest.integration.DataCenter} because not all regions support
+     * app files yet.
+     */
+    enum Region {
+        EU_CENTRAL, US_WEST
     }
 }
\ No newline at end of file
diff --git a/src/test/java/com/saucelabs/saucerest/integration/SauceConnectTest.java b/src/test/java/com/saucelabs/saucerest/integration/SauceConnectTest.java
index 6672d4d2..26ebab55 100644
--- a/src/test/java/com/saucelabs/saucerest/integration/SauceConnectTest.java
+++ b/src/test/java/com/saucelabs/saucerest/integration/SauceConnectTest.java
@@ -21,6 +21,25 @@
  */
 public class SauceConnectTest {
 
+    @AfterAll
+    @SuppressWarnings("all")
+    public static void tearDown() throws IOException {
+        for (DataCenter dataCenter : DataCenter.values()) {
+            SauceREST sauceREST = new SauceREST(dataCenter);
+            SauceConnect sauceConnect = sauceREST.getSauceConnect();
+
+            List<String> tunnelIDs = sauceConnect.getTunnelsForAUser();
+
+            for (String tunnelID : tunnelIDs) {
+                StopTunnel stopTunnel = sauceConnect.stopTunnel(tunnelID);
+
+                Assertions.assertTrue(stopTunnel.result);
+                Assertions.assertFalse(stopTunnel.id.isEmpty());
+                Assertions.assertNotNull(stopTunnel.jobsRunning);
+            }
+        }
+    }
+
     @ParameterizedTest
     @EnumSource(DataCenter.class)
     public void getLatestVersionTest(DataCenter dataCenter) throws IOException {
@@ -61,25 +80,6 @@ public void getLatestVersionWithoutCredentialsTest(DataCenter dataCenter) throws
         Assertions.assertFalse(versions.downloads.win32.sha1.isEmpty());
     }
 
-    @AfterAll
-    @SuppressWarnings("all")
-    public static void tearDown() throws IOException {
-        for (DataCenter dataCenter : DataCenter.values()) {
-            SauceREST sauceREST = new SauceREST(dataCenter);
-            SauceConnect sauceConnect = sauceREST.getSauceConnect();
-
-            List<String> tunnelIDs = sauceConnect.getTunnelsForAUser();
-
-            for (String tunnelID : tunnelIDs) {
-                StopTunnel stopTunnel = sauceConnect.stopTunnel(tunnelID);
-
-                Assertions.assertTrue(stopTunnel.result);
-                Assertions.assertFalse(stopTunnel.id.isEmpty());
-                Assertions.assertNotNull(stopTunnel.jobsRunning);
-            }
-        }
-    }
-
     @ParameterizedTest
     @EnumSource(value = DataCenter.class, names = {"EU_CENTRAL", "US_WEST", "APAC_SOUTHEAST"}, mode = EnumSource.Mode.INCLUDE)
     public void getTunnelsForAUserTest(DataCenter dataCenter) throws IOException {
diff --git a/src/test/java/com/saucelabs/saucerest/integration/StorageTest.java b/src/test/java/com/saucelabs/saucerest/integration/StorageTest.java
index 0f0c18b4..3b643470 100644
--- a/src/test/java/com/saucelabs/saucerest/integration/StorageTest.java
+++ b/src/test/java/com/saucelabs/saucerest/integration/StorageTest.java
@@ -2,7 +2,9 @@
 
 import com.google.common.collect.ImmutableMap;
 import com.saucelabs.saucerest.DataCenter;
+import com.saucelabs.saucerest.SauceException;
 import com.saucelabs.saucerest.SauceREST;
+import com.saucelabs.saucerest.api.AbstractEndpoint;
 import com.saucelabs.saucerest.api.Storage;
 import com.saucelabs.saucerest.model.storage.*;
 import org.junit.jupiter.api.AfterEach;
@@ -17,22 +19,16 @@
 import java.nio.file.Path;
 import java.nio.file.Paths;
 import java.util.Objects;
+import java.util.logging.Logger;
+
+import static org.junit.jupiter.api.Assertions.assertThrows;
 
 public class StorageTest {
     private final ThreadLocal<Storage> storage = new ThreadLocal<>();
+    private static final Logger logger = Logger.getLogger(AbstractEndpoint.class.getName());
 
-//    private static final Storage euCentralStorage = new SauceREST(DataCenter.EU_CENTRAL).getStorage();
-//    private static final Storage usWestStorage = new SauceREST(DataCenter.US_WEST).getStorage();
-@TempDir
-private Path tempDir;
-
-    /**
-     * Use this instead of {@link com.saucelabs.saucerest.integration.DataCenter} because not all regions support
-     * app files yet.
-     */
-    enum Region {
-        EU_CENTRAL, US_WEST
-    }
+    @TempDir
+    private Path tempDir;
 
     private EditAppGroupSettings getAppGroupResetSettings(EditAppGroupSettings.Builder.Platform platform) {
         if (platform.equals(EditAppGroupSettings.Builder.Platform.ANDROID)) {
@@ -75,54 +71,26 @@ public void setup(Region region) {
     }
 
     @AfterEach
-    public void resetAppGroupSettings() throws IOException {
-        for (ItemInteger itemInteger : storage.get().getGroups().items) {
-            if (EditAppGroupSettings.Builder.Platform.fromString(itemInteger.recent.kind).equals(EditAppGroupSettings.Builder.Platform.ANDROID)) {
-                try {
-                    storage.get().updateAppStorageGroupSettings(itemInteger.id, Objects.requireNonNull(getAppGroupResetSettings(EditAppGroupSettings.Builder.Platform.ANDROID)));
-                } catch (IOException ignored) {
-                    System.out.println("Failed to reset app group settings for " + itemInteger.recent.name + " (" + itemInteger.id + ")" + " in EU Central");
-                }
-            } else if (EditAppGroupSettings.Builder.Platform.fromString(itemInteger.recent.kind).equals(EditAppGroupSettings.Builder.Platform.IOS)) {
-                try {
-                    storage.get().updateAppStorageGroupSettings(itemInteger.id, Objects.requireNonNull(getAppGroupResetSettings(EditAppGroupSettings.Builder.Platform.IOS)));
-                } catch (IOException ignored) {
-                    System.out.println("Failed to reset app group settings for " + itemInteger.recent.name + " (" + itemInteger.id + ")" + " in EU Central");
+    public void resetAppGroupSettings() {
+        try {
+            for (ItemInteger itemInteger : storage.get().getGroups().items) {
+                if (EditAppGroupSettings.Builder.Platform.fromString(itemInteger.recent.kind).equals(EditAppGroupSettings.Builder.Platform.ANDROID)) {
+                    try {
+                        storage.get().updateAppStorageGroupSettings(itemInteger.id, Objects.requireNonNull(getAppGroupResetSettings(EditAppGroupSettings.Builder.Platform.ANDROID)));
+                    } catch (IOException ignored) {
+                        System.out.println("Failed to reset app group settings for " + itemInteger.recent.name + " (" + itemInteger.id + ")" + " in EU Central");
+                    }
+                } else if (EditAppGroupSettings.Builder.Platform.fromString(itemInteger.recent.kind).equals(EditAppGroupSettings.Builder.Platform.IOS)) {
+                    try {
+                        storage.get().updateAppStorageGroupSettings(itemInteger.id, Objects.requireNonNull(getAppGroupResetSettings(EditAppGroupSettings.Builder.Platform.IOS)));
+                    } catch (IOException ignored) {
+                        System.out.println("Failed to reset app group settings for " + itemInteger.recent.name + " (" + itemInteger.id + ")" + " in EU Central");
+                    }
                 }
             }
+        } catch (IOException | SauceException e) {
+            logger.warning("Failed to reset app group settings" + e.getMessage());
         }
-
-//        for (ItemInteger itemInteger : euCentralStorage.getGroups().items) {
-//            if (EditAppGroupSettings.Builder.Platform.fromString(itemInteger.recent.kind).equals(EditAppGroupSettings.Builder.Platform.ANDROID)) {
-//                try {
-//                    euCentralStorage.updateAppStorageGroupSettings(itemInteger.id, Objects.requireNonNull(getAppGroupResetSettings(EditAppGroupSettings.Builder.Platform.ANDROID)));
-//                } catch (IOException ignored) {
-//                    System.out.println("Failed to reset app group settings for " + itemInteger.recent.name + " (" + itemInteger.id + ")" + " in EU Central");
-//                }
-//            } else if (EditAppGroupSettings.Builder.Platform.fromString(itemInteger.recent.kind).equals(EditAppGroupSettings.Builder.Platform.IOS)) {
-//                try {
-//                    euCentralStorage.updateAppStorageGroupSettings(itemInteger.id, Objects.requireNonNull(getAppGroupResetSettings(EditAppGroupSettings.Builder.Platform.IOS)));
-//                } catch (IOException ignored) {
-//                    System.out.println("Failed to reset app group settings for " + itemInteger.recent.name + " (" + itemInteger.id + ")" + " in EU Central");
-//                }
-//            }
-//        }
-//
-//        for (ItemInteger itemInteger : usWestStorage.getGroups().items) {
-//            if (EditAppGroupSettings.Builder.Platform.fromString(itemInteger.recent.kind).equals(EditAppGroupSettings.Builder.Platform.ANDROID)) {
-//                try {
-//                    usWestStorage.updateAppStorageGroupSettings(itemInteger.id, Objects.requireNonNull(getAppGroupResetSettings(EditAppGroupSettings.Builder.Platform.ANDROID)));
-//                } catch (IOException ignored) {
-//                    System.out.println("Failed to reset app group settings for " + itemInteger.recent.name + " (" + itemInteger.id + ")" + " in US West");
-//                }
-//            } else if (EditAppGroupSettings.Builder.Platform.fromString(itemInteger.recent.kind).equals(EditAppGroupSettings.Builder.Platform.IOS)) {
-//                try {
-//                    usWestStorage.updateAppStorageGroupSettings(itemInteger.id, Objects.requireNonNull(getAppGroupResetSettings(EditAppGroupSettings.Builder.Platform.IOS)));
-//                } catch (IOException ignored) {
-//                    System.out.println("Failed to reset app group settings for " + itemInteger.recent.name + " (" + itemInteger.id + ")" + " in US West");
-//                }
-//            }
-//        }
     }
 
     @ParameterizedTest
@@ -384,4 +352,28 @@ public void deleteAppGroup(Region region) throws IOException {
         int groupIdOfDeletedGroup = deleteAppGroupFiles.item.id;
         Assertions.assertEquals(groupIdOfDeletedGroup, groupId);
     }
+
+    @ParameterizedTest
+    @EnumSource(Region.class)
+    public void appNotFoundTest(Region region) throws IOException {
+        setup(region);
+
+        assertThrows(SauceException.NotFound.class, () -> storage.get().deleteFile("abc123"));
+    }
+
+    @ParameterizedTest
+    @EnumSource(Region.class)
+    public void appGroupNotFoundTest(Region region) throws IOException {
+        setup(region);
+
+        assertThrows(SauceException.NotFound.class, () -> storage.get().deleteFileGroup(123456789));
+    }
+
+    /**
+     * Use this instead of {@link com.saucelabs.saucerest.integration.DataCenter} because not all regions support
+     * app files yet.
+     */
+    enum Region {
+        EU_CENTRAL, US_WEST
+    }
 }
\ No newline at end of file
diff --git a/src/test/java/com/saucelabs/saucerest/integration/StorageTestHelper.java b/src/test/java/com/saucelabs/saucerest/integration/StorageTestHelper.java
index 8eee7af3..a7d2a728 100644
--- a/src/test/java/com/saucelabs/saucerest/integration/StorageTestHelper.java
+++ b/src/test/java/com/saucelabs/saucerest/integration/StorageTestHelper.java
@@ -4,6 +4,10 @@
 import java.util.Objects;
 
 public class StorageTestHelper {
+    public File getAppFile(AppFile appFile) {
+        return new File(Objects.requireNonNull(getClass().getResource("/AppFiles/" + appFile.fileName)).getFile());
+    }
+
     enum AppFile {
         IPA("iOS-Real-Device-MyRNDemoApp.ipa"),
         ZIP("iOS-Simulator-MyRNDemoApp.zip"),
@@ -17,8 +21,4 @@ enum AppFile {
             this.fileName = fileName;
         }
     }
-
-    public File getAppFile(AppFile appFile) {
-        return new File(Objects.requireNonNull(getClass().getResource("/AppFiles/" + appFile.fileName)).getFile());
-    }
-}
+}
\ No newline at end of file
diff --git a/src/test/java/com/saucelabs/saucerest/unit/CreateUserTest.java b/src/test/java/com/saucelabs/saucerest/unit/CreateUserTest.java
new file mode 100644
index 00000000..e5672368
--- /dev/null
+++ b/src/test/java/com/saucelabs/saucerest/unit/CreateUserTest.java
@@ -0,0 +1,44 @@
+package com.saucelabs.saucerest.unit;
+
+import com.saucelabs.saucerest.model.accounts.CreateUser;
+import com.saucelabs.saucerest.model.accounts.Roles;
+import org.junit.jupiter.api.Test;
+
+import java.util.Arrays;
+import java.util.List;
+
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+public class CreateUserTest {
+
+    @Test
+    public void checkParameterTest() {
+        List<String> passwords = Arrays.asList("testtest", "testtest1", "testtest!", "testtest1!", "testTEST1", "test");
+
+        for (String password : passwords) {
+            assertThrows(IllegalArgumentException.class, () ->
+                new CreateUser.Builder()
+                    .setUserName("test")
+                    .setFirstName("test")
+                    .setLastName("test")
+                    .setEmail("test@example.com")
+                    .setOrganization("test")
+                    .setRole(Roles.MEMBER)
+                    .setPassword(password)
+                    .build());
+        }
+
+        assertDoesNotThrow(() -> {
+            new CreateUser.Builder()
+                .setUserName("test")
+                .setFirstName("test")
+                .setLastName("test")
+                .setEmail("test@example.com")
+                .setOrganization("test")
+                .setRole(Roles.MEMBER)
+                .setPassword("testTEST1!")
+                .build();
+        });
+    }
+}
\ No newline at end of file
diff --git a/src/test/java/com/saucelabs/saucerest/unit/SauceRESTTest.java b/src/test/java/com/saucelabs/saucerest/unit/SauceRESTTest.java
index 9ce3a3e9..fb3d3f4c 100644
--- a/src/test/java/com/saucelabs/saucerest/unit/SauceRESTTest.java
+++ b/src/test/java/com/saucelabs/saucerest/unit/SauceRESTTest.java
@@ -30,6 +30,7 @@
 import static org.hamcrest.Matchers.containsString;
 import static org.hamcrest.Matchers.not;
 import static org.junit.jupiter.api.Assertions.*;
+
 @Execution(ExecutionMode.SAME_THREAD)
 class SauceRESTTest {
 
@@ -453,7 +454,7 @@ void testDownloadServerLog(@TempDir Path tempDir) {
     @Test
     void testDownloadServerLogWithCustomFileName(@TempDir Path tempDir) throws Exception {
         urlConnection.setResponseCode(200);
-        urlConnection.setInputStream(new ByteArrayInputStream("{ }".getBytes(StandardCharsets.UTF_8.name())));
+        urlConnection.setInputStream(new ByteArrayInputStream("{ }".getBytes(StandardCharsets.UTF_8)));
 
         String absolutePath = tempDir.toAbsolutePath().toString();
         boolean downloaded = sauceREST.downloadServerLog("1234", absolutePath, "foobar.log");
@@ -471,7 +472,7 @@ void testDownloadServerLogWithCustomFileName(@TempDir Path tempDir) throws Excep
     @Test
     void testDownloadServerLogWithCustomFileNameEmptyDefaultFallback(@TempDir Path tempDir) throws Exception {
         urlConnection.setResponseCode(200);
-        urlConnection.setInputStream(new ByteArrayInputStream("{ }".getBytes(StandardCharsets.UTF_8.name())));
+        urlConnection.setInputStream(new ByteArrayInputStream("{ }".getBytes(StandardCharsets.UTF_8)));
 
         String absolutePath = tempDir.toAbsolutePath().toString();
         boolean downloaded = sauceREST.downloadServerLog("1234", absolutePath, "");
@@ -489,7 +490,7 @@ void testDownloadServerLogWithCustomFileNameEmptyDefaultFallback(@TempDir Path t
     @Test
     void testDownloadServerLogWithCustomFileNameSlashed(@TempDir Path tempDir) throws Exception {
         urlConnection.setResponseCode(200);
-        urlConnection.setInputStream(new ByteArrayInputStream("{ }".getBytes(StandardCharsets.UTF_8.name())));
+        urlConnection.setInputStream(new ByteArrayInputStream("{ }".getBytes(StandardCharsets.UTF_8)));
 
         String absolutePath = tempDir.toAbsolutePath().toString();
         boolean downloaded = sauceREST.downloadServerLog("1234", absolutePath, "foo/bar.log");
@@ -532,7 +533,7 @@ void testDownloadAutomatorLog(@TempDir Path tempDir) {
     @Test
     void testDownloadAutomatorLogWithCustomFileName(@TempDir Path tempDir) throws Exception {
         urlConnection.setResponseCode(200);
-        urlConnection.setInputStream(new ByteArrayInputStream("{ }".getBytes(StandardCharsets.UTF_8.name())));
+        urlConnection.setInputStream(new ByteArrayInputStream("{ }".getBytes(StandardCharsets.UTF_8)));
 
         String absolutePath = tempDir.toAbsolutePath().toString();
         boolean downloaded = sauceREST.downloadAutomatorLog("1234", absolutePath, "foobar.log");
@@ -610,7 +611,7 @@ void testDownloadScreenshots(@TempDir Path tempDir) {
     @Test
     void testDownloadScreenshotsWithCustomFileName(@TempDir Path tempDir) throws Exception {
         urlConnection.setResponseCode(200);
-        urlConnection.setInputStream(new ByteArrayInputStream("{ }".getBytes(StandardCharsets.UTF_8.name())));
+        urlConnection.setInputStream(new ByteArrayInputStream("{ }".getBytes(StandardCharsets.UTF_8)));
 
         String absolutePath = tempDir.toAbsolutePath().toString();
         boolean downloaded = sauceREST.downloadScreenshots("1234", absolutePath, "foobar.zip");
@@ -695,7 +696,7 @@ void testDownloadHARWithWrongCredentialsThrowsException(@TempDir Path tempDir) {
     @Test
     void testDownloadSauceLabsLog(@TempDir Path tempDir) throws Exception {
         urlConnection.setResponseCode(200);
-        urlConnection.setInputStream(new ByteArrayInputStream("{ }".getBytes(StandardCharsets.UTF_8.name())));
+        urlConnection.setInputStream(new ByteArrayInputStream("{ }".getBytes(StandardCharsets.UTF_8)));
 
         boolean downloaded = sauceREST.downloadSauceLabsLog("1234", tempDir.toAbsolutePath().toString());
         assertEquals(
@@ -713,7 +714,7 @@ void testDownloadSauceLabsLog(@TempDir Path tempDir) throws Exception {
     @Test
     void testDownloadSauceLabsLogStream() throws Exception {
         urlConnection.setResponseCode(200);
-        urlConnection.setInputStream(new ByteArrayInputStream("{ }".getBytes(StandardCharsets.UTF_8.name())));
+        urlConnection.setInputStream(new ByteArrayInputStream("{ }".getBytes(StandardCharsets.UTF_8)));
 
         byte[] targetArray;
         try (BufferedInputStream stream = sauceREST.downloadSauceLabsLog("1234")) {
@@ -1247,4 +1248,4 @@ void testGetTunnelInformation() {
 
     }
     */
-}
+}
\ No newline at end of file
diff --git a/src/test/resources/logging.properties b/src/test/resources/logging.properties
index d9ce495a..0dfb82ca 100644
--- a/src/test/resources/logging.properties
+++ b/src/test/resources/logging.properties
@@ -1,3 +1,3 @@
-.level=OFF
+.level=INFO
 handlers=java.util.logging.ConsoleHandler
-java.util.logging.ConsoleHandler.level=OFF
\ No newline at end of file
+java.util.logging.ConsoleHandler.level=INFO
\ No newline at end of file