diff --git a/.gitattributes b/.gitattributes
new file mode 100644
index 0000000000000000000000000000000000000000..a612c0c5a35974f06e09e2d4d36bfed37630805b
--- /dev/null
+++ b/.gitattributes
@@ -0,0 +1,15 @@
+tests/ export-ignore
+vendor/ export-ignore
+.editorconfig export-ignore
+.gitattributes export-ignore
+.gitignore export-ignore
+.git/ export-ignore
+.gitlab-ci.yml export-ignore
+.idea export-ignore
+apigen.neon export-ignore
+build-coverage/ export-ignore
+docs/ export-ignore
+LICENSE.md export-ignore
+phpcs.xml.dist export-ignore
+phpunit-integration.xml export-ignore
+phpunit-unit.xml export-ignore
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..4b86223d6cae8ddb86d7cc3d12e0fcca43717f54
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,5 @@
+/vendor/
+.idea
+composer.lock
+build-coverage
+swagger
\ No newline at end of file
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
new file mode 100644
index 0000000000000000000000000000000000000000..db521c16d8bda63ee8608498ded2b1e6665ea5d0
--- /dev/null
+++ b/.gitlab-ci.yml
@@ -0,0 +1,6 @@
+variables:
+  DISABLE_ACCEPTANCE: "1"
+  DISABLE_FUNCTIONAL: "1"
+
+include: 'https://gitlab.com/wpdesk/gitlab-ci/raw/master/gitlab-ci-1.2.yml'
+
diff --git a/README.md b/README.md
index b6395ced1ce86a8e1b996dc337afea525a73484c..a8ccb8632fa21d89aadcc1eafb762fc90de91f06 100644
--- a/README.md
+++ b/README.md
@@ -1,2 +1,6 @@
-# wp-api-client
+[![pipeline status](https://gitlab.com/wpdesk/wp-api-client/badges/master/pipeline.svg)](https://gitlab.com/wpdesk/wp-api-client/commits/master) 
+Integration: [![coverage report](https://gitlab.com/wpdesk/wp-api-client/badges/master/coverage.svg?job=integration+test+lastest+coverage)](https://gitlab.com/wpdesk/wp-api-client/commits/master)
+Unit: [![coverage report](https://gitlab.com/wpdesk/wp-api-client/badges/master/coverage.svg?job=unit+test+lastest+coverage)](https://gitlab.com/wpdesk/wp-api-client/commits/master)
 
+API Client
+==========
diff --git a/changelog.txt b/changelog.txt
new file mode 100644
index 0000000000000000000000000000000000000000..03dc5509a4b06623a6e810075e831cf3beb91021
--- /dev/null
+++ b/changelog.txt
@@ -0,0 +1,2 @@
+= 1.0 - 2019-01-31 =
+* First release
diff --git a/composer.json b/composer.json
new file mode 100644
index 0000000000000000000000000000000000000000..6980cec0a9880f590c8dfcdc3110db1a6f8de345
--- /dev/null
+++ b/composer.json
@@ -0,0 +1,35 @@
+{
+  "name": "wpdesk/wp-api-client",
+  "authors": [
+    {
+      "name": "Krzysiek",
+      "email": "krzysiek@wpdesk.pl"
+    }
+  ],
+  "require": {
+    "php": ">=5.5",
+    "psr/log": "^1.0.1",
+    "wpdesk/wp-http-client": "dev-master",
+    "psr/simple-cache": "^1.0"
+  },
+  "require-dev": {
+    "phpunit/phpunit": "<7",
+    "wp-coding-standards/wpcs": "^0.14.1",
+    "squizlabs/php_codesniffer": "^3.0.2",
+    "mockery/mockery": "*",
+    "10up/wp_mock": "*"
+  },
+  "autoload": {
+    "psr-4": {
+      "WPDesk\\ApiClient\\": "src/"
+    }
+  },
+  "autoload-dev": {
+  },
+  "scripts": {
+    "phpunit-unit": "phpunit --configuration phpunit-unit.xml --coverage-text --colors=never",
+    "phpunit-unit-fast": "phpunit --configuration phpunit-unit.xml --no-coverage",
+    "phpunit-integration": "phpunit --configuration phpunit-integration.xml --coverage-text --colors=never",
+    "phpunit-integration-fast": "phpunit --configuration phpunit-integration.xml --no-coverage"
+  }
+}
diff --git a/phpunit-integration.xml b/phpunit-integration.xml
new file mode 100644
index 0000000000000000000000000000000000000000..4a342abf125d638d044bafa01cd9a75a771b4b3d
--- /dev/null
+++ b/phpunit-integration.xml
@@ -0,0 +1,28 @@
+<phpunit bootstrap="tests/integration/bootstrap.php"
+         backupGlobals="false"
+     >
+    <testsuites>
+        <testsuite>
+            <directory prefix="Test" suffix=".php">./tests/integration</directory>
+        </testsuite>
+    </testsuites>
+
+    <filter>
+        <whitelist>
+            <directory suffix=".php">src</directory>
+        </whitelist>
+    </filter>
+
+    <logging>
+        <log type="junit" target="build-coverage/report.junit.xml"/>
+        <log type="coverage-html" target="build-coverage/coverage" charset="UTF-8" yui="true" highlight="true"/>
+        <log type="coverage-text" target="build-coverage/coverage.txt"/>
+        <log type="coverage-clover" target="build-coverage/clover.xml"/>
+    </logging>
+
+    <php>
+        <env name="WP_DEVELOP_DIR" value="/tmp/wordpress-develop"/>
+        <env name="WC_DEVELOP_DIR" value="/tmp/woocommerce"/>
+    </php>
+
+</phpunit>
\ No newline at end of file
diff --git a/phpunit-unit.xml b/phpunit-unit.xml
new file mode 100644
index 0000000000000000000000000000000000000000..31e5c9f9c202769cac9487ac192f331e827c9489
--- /dev/null
+++ b/phpunit-unit.xml
@@ -0,0 +1,21 @@
+<phpunit bootstrap="tests/unit/bootstrap.php">
+    <testsuites>
+        <testsuite>
+            <directory prefix="Test" suffix=".php">./tests/unit/</directory>
+        </testsuite>
+    </testsuites>
+
+    <filter>
+        <whitelist>
+            <directory suffix=".php">src</directory>
+        </whitelist>
+    </filter>
+
+    <logging>
+        <log type="junit" target="build-coverage/report.junit.xml"/>
+        <log type="coverage-html" target="build-coverage/coverage" charset="UTF-8" yui="true" highlight="true"/>
+        <log type="coverage-text" target="build-coverage/coverage.txt"/>
+        <log type="coverage-clover" target="build-coverage/clover.xml"/>
+    </logging>
+
+</phpunit>
diff --git a/src/ApiClient/CachedClient.php b/src/ApiClient/CachedClient.php
new file mode 100644
index 0000000000000000000000000000000000000000..a7f512c2a97ab2827fe8ca83151bc0ee60735470
--- /dev/null
+++ b/src/ApiClient/CachedClient.php
@@ -0,0 +1,111 @@
+<?php
+
+namespace WPDesk\SaasPlatformClient\ApiClient;
+
+use Psr\SimpleCache\CacheInterface;
+use WPDesk\SaasPlatformClient\Cache\CacheDispatcher;
+use WPDesk\SaasPlatformClient\Cache\CacheItemCreator;
+use WPDesk\SaasPlatformClient\Cache\CacheItemVerifier;
+use WPDesk\SaasPlatformClient\HttpClient\HttpClient;
+use WPDesk\SaasPlatformClient\Request\Request;
+use WPDesk\SaasPlatformClient\Response\Response;
+use WPDesk\SaasPlatformClient\Serializer\Serializer;
+
+class CachedClient implements Client, CacheItemCreator, CacheItemVerifier
+{
+
+    /** @var Client */
+    private $client;
+
+    /** @var CacheInterface */
+    private $cache;
+
+    /**
+     * @var CacheDispatcher
+     */
+    private $cacheDispatcher;
+
+    /**
+     * CachedClient constructor.
+     * @param Client $decorated Decorated client
+     * @param CacheInterface $cache
+     */
+    public function __construct(Client $decorated, CacheInterface $cache)
+    {
+        $this->client = $decorated;
+        $this->cache = $cache;
+        $this->cacheDispatcher = new CacheDispatcher($cache, [new RequestCacheInfoResolver()]);
+    }
+
+    /**
+     * Create item to cache.
+     *
+     * @param Request $request
+     * @return Response
+     */
+    public function createCacheItem($request)
+    {
+        return $this->client->sendRequest($request);
+    }
+
+    /**
+     * Verify cache item.
+     *
+     * @param $object
+     * @return Response;
+     */
+    public function getVerifiedItemOrNull($object)
+    {
+        if ($object instanceof Response) {
+            return $object;
+        }
+        return null;
+    }
+
+    /**
+     * Send request.
+     *
+     * @param Request $request
+     * @return mixed|Response
+     * @throws \Psr\SimpleCache\InvalidArgumentException
+     */
+    public function sendRequest(Request $request)
+    {
+        $response = $this->cacheDispatcher->dispatch($request, $this, $this);
+        return $response;
+    }
+
+    /**
+     * @return HttpClient
+     */
+    public function getHttpClient()
+    {
+        return $this->client->getHttpClient();
+    }
+
+    /**
+     * @param HttpClient $client
+     * @return mixed
+     */
+    public function setHttpClient(HttpClient $client)
+    {
+        return $this->client->setHttpClient($client);
+    }
+
+    /**
+     * @return Serializer
+     */
+    public function getSerializer()
+    {
+        return $this->client->getSerializer();
+    }
+
+    /**
+     * @return string
+     */
+    public function getApiUrl()
+    {
+        return $this->client->getApiUrl();
+    }
+
+}
\ No newline at end of file
diff --git a/src/ApiClient/Client.php b/src/ApiClient/Client.php
new file mode 100644
index 0000000000000000000000000000000000000000..993f5caafc60b9207476c9db51a71ba872041110
--- /dev/null
+++ b/src/ApiClient/Client.php
@@ -0,0 +1,41 @@
+<?php
+
+namespace WPDesk\SaasPlatformClient\ApiClient;
+
+use WPDesk\SaasPlatformClient\HttpClient\HttpClient;
+use WPDesk\SaasPlatformClient\Request\Request;
+use WPDesk\SaasPlatformClient\Response\Response;
+use WPDesk\SaasPlatformClient\Serializer\Serializer;
+
+interface Client
+{
+    /**
+     * Send given request trough HttpClient
+     *
+     * @param Request $request
+     * @return Response
+     */
+    public function sendRequest(Request $request);
+
+    /**
+     * @return HttpClient
+     */
+    public function getHttpClient();
+
+    /**
+     * @param HttpClient $client
+     */
+    public function setHttpClient(HttpClient $client);
+
+    /**
+     * @return Serializer
+     */
+    public function getSerializer();
+
+    /**
+     * Returns api url. Always without ending /
+     *
+     * @return string
+     */
+    public function getApiUrl();
+}
\ No newline at end of file
diff --git a/src/ApiClient/ClientFactory.php b/src/ApiClient/ClientFactory.php
new file mode 100644
index 0000000000000000000000000000000000000000..a5b45e6b6d53a2eb85c44da2c3f3ec6ab478d123
--- /dev/null
+++ b/src/ApiClient/ClientFactory.php
@@ -0,0 +1,35 @@
+<?php
+
+namespace WPDesk\SaasPlatformClient\ApiClient;
+
+use WPDesk\SaasPlatformClient\Cache\WordpressCache;
+use WPDesk\SaasPlatformClient\HttpClient\HttpClientFactory;
+use WPDesk\SaasPlatformClient\PlatformFactoryOptions;
+use WPDesk\SaasPlatformClient\Serializer\SerializerFactory;
+
+class ClientFactory
+{
+    /**
+     * @param PlatformFactoryOptions $options
+     * @return Client
+     */
+    public function createClient(PlatformFactoryOptions $options)
+    {
+        $httpClientFactory = new HttpClientFactory();
+        $serializerFactory = new SerializerFactory();
+
+        $client = new ClientImplementation(
+            $httpClientFactory->createClient($options),
+            $serializerFactory->createSerializer($options),
+            $options->getLogger(),
+            $options->getApiUrl(),
+            $options->getDefaultRequestHeaders()
+        );
+
+        if ($options->isCachedClient()) {
+            $client = new CachedClient($client, new WordpressCache());
+        }
+
+        return $client;
+    }
+}
\ No newline at end of file
diff --git a/src/ApiClient/ClientImplementation.php b/src/ApiClient/ClientImplementation.php
new file mode 100644
index 0000000000000000000000000000000000000000..6153d4ca5ec0d5ad97359b7211dfd01d4bd6ff59
--- /dev/null
+++ b/src/ApiClient/ClientImplementation.php
@@ -0,0 +1,215 @@
+<?php
+
+namespace WPDesk\SaasPlatformClient\ApiClient;
+
+use Psr\Log\LoggerAwareInterface;
+use Psr\Log\LoggerInterface;
+use WPDesk\SaasPlatformClient\HttpClient\HttpClient;
+use WPDesk\SaasPlatformClient\HttpClient\HttpClientResponse;
+use WPDesk\SaasPlatformClient\Platform;
+use WPDesk\SaasPlatformClient\Request\Request;
+use WPDesk\SaasPlatformClient\Response\RawResponse;
+use WPDesk\SaasPlatformClient\Response\Response;
+use WPDesk\SaasPlatformClient\Serializer\Serializer;
+use WPDesk\SaasPlatformClient\HttpClient\HttpClientRequestException;
+
+class ClientImplementation implements Client, LoggerAwareInterface
+{
+    const CLIENT_VERSION = '1.6.5';
+
+    const DEFAULT_TIMEOUT = 10;
+
+    /** @var HttpClient */
+    private $client;
+
+    /** @var Serializer */
+    private $serializer;
+
+    /** @var LoggerInterface */
+    private $logger;
+
+    /** @var string */
+    private $apiUrl;
+
+    /** @var array */
+    private $defaultRequestHeaders;
+
+    /**
+     * Client constructor.
+     * @param HttpClient $client
+     * @param Serializer $serializer
+     * @param LoggerInterface $logger
+     * @param string $apiUri
+     * @param array $defaultRequestHeaders
+     */
+    public function __construct(
+        HttpClient $client,
+        Serializer $serializer,
+        LoggerInterface $logger,
+        $apiUri,
+        array $defaultRequestHeaders
+    ) {
+        $this->client = $client;
+        $this->serializer = $serializer;
+        $this->logger = $logger;
+        $this->apiUrl = $apiUri;
+        $this->defaultRequestHeaders = $defaultRequestHeaders;
+    }
+
+    /**
+     * Send given request trough HttpClient
+     *
+     * @param Request $request
+     * @throws HttpClientRequestException
+     * @return Response
+     */
+    public function sendRequest(Request $request)
+    {
+        $this->logger->debug("Sends request with METHOD: {$request->getMethod()}; to ENDPOINT {$request->getEndpoint()}",
+            $this->getLoggerContext());
+        try {
+            $httpResponse = $this->client->send(
+                $fullUrl = $this->prepareFullUrl($request),
+                $method = $request->getMethod(),
+                $body = $this->prepareRequestBody($request),
+                $headers = $this->prepareRequestHeaders($request), self::DEFAULT_TIMEOUT
+            );
+
+            $this->logger->debug(
+                "Sent request with: URL: {$fullUrl};\n METHOD: {$method};\n BODY: {$body};\n"
+                . "HEADERS: " . json_encode($headers) . "\n\n and got response as CODE: {$httpResponse->getResponseCode()};\n"
+                . "with RESPONSE BODY {$httpResponse->getBody()}",
+                $this->getLoggerContext());
+
+
+            return $this->mapHttpResponseToApiResponse($httpResponse);
+        } catch (HttpClientRequestException $e) {
+            $this->logger->error("Exception {$e->getMessage()}; {$e->getCode()} occurred while sending request");
+            throw $e;
+        }
+    }
+
+    /**
+     * Returns full request url with endpoint
+     *
+     * @param Request $request
+     * @return string
+     */
+    private function prepareFullUrl(Request $request)
+    {
+        $endpoint = $request->getEndpoint();
+        if (strpos('http', $endpoint) === 0) {
+            return $endpoint;
+        }
+        return $this->getApiUrl() . $endpoint;
+    }
+
+    /**
+     * Map response from http client to api response using serializer
+     *
+     * @param HttpClientResponse $response
+     * @return RawResponse
+     */
+    private function mapHttpResponseToApiResponse(HttpClientResponse $response)
+    {
+        $apiResponse = new RawResponse(
+            $this->serializer->unserialize($response->getBody()),
+            $response->getResponseCode(),
+            $response->getHeaders()
+        );
+
+        return $apiResponse;
+    }
+
+    /**
+     * Prepare serialized request body
+     *
+     * @param Request $request
+     * @return string
+     */
+    private function prepareRequestBody(Request $request)
+    {
+        return $this->serializer->serialize($request->getBody());
+    }
+
+    /**
+     * Prepares array of http headers
+     *
+     * @param Request $request
+     * @return array
+     */
+    private function prepareRequestHeaders(Request $request)
+    {
+        $headers = array(
+            'User-Agent' => 'saas-client-' . self::CLIENT_VERSION,
+            'Accept-Encoding' => '*',
+            'Content-Type' => $this->serializer->getMime()
+        );
+        $headers = array_merge($this->defaultRequestHeaders, $headers);
+        return array_merge($headers, $request->getHeaders());
+    }
+
+    /**
+     * @return HttpClient
+     */
+    public function getHttpClient()
+    {
+        return $this->client;
+    }
+
+    /**
+     * @param HttpClient $client
+     */
+    public function setHttpClient(HttpClient $client)
+    {
+        $this->client = $client;
+    }
+
+    /**
+     * @return Serializer
+     */
+    public function getSerializer()
+    {
+        return $this->serializer;
+    }
+
+    /**
+     * Returns api url. Always without ending /
+     *
+     * @return string
+     */
+    public function getApiUrl()
+    {
+        return trim($this->apiUrl, '/');
+    }
+
+    /**
+     * Sets logger
+     *
+     * @param LoggerInterface $logger
+     */
+    public function setLogger(LoggerInterface $logger)
+    {
+        $this->logger = $logger;
+    }
+
+    /**
+     * Returns logger context for
+     *
+     * @param string $additional_context Optional additional context
+     * @return array
+     */
+    protected function getLoggerContext($additional_context = '')
+    {
+        $context = [
+            Platform::LIBARY_LOGIN_CONTEXT,
+            self::class
+        ];
+        if ($additional_context !== '') {
+            $context[] = $additional_context;
+        }
+        return $context;
+    }
+
+
+}
\ No newline at end of file
diff --git a/src/ApiClient/RequestCacheInfoResolver.php b/src/ApiClient/RequestCacheInfoResolver.php
new file mode 100644
index 0000000000000000000000000000000000000000..65e2014b4dd863bc3a1503b16f7fb6b2c4839c20
--- /dev/null
+++ b/src/ApiClient/RequestCacheInfoResolver.php
@@ -0,0 +1,139 @@
+<?php
+
+namespace WPDesk\SaasPlatformClient\ApiClient;
+
+use WPDesk\SaasPlatformClient\Cache\CacheInfoResolver;
+use WPDesk\SaasPlatformClient\Cache\HowToCache;
+use WPDesk\SaasPlatformClient\Request\AuthRequest;
+use WPDesk\SaasPlatformClient\Request\BasicRequest;
+use WPDesk\SaasPlatformClient\Request\Request;
+use WPDesk\SaasPlatformClient\Request\ShippingServicesSettings\PutSettingsRequest;
+use WPDesk\SaasPlatformClient\Request\Status\GetStatusRequest;
+use WPDesk\SaasPlatformClient\Response\ApiResponse;
+use WPDesk\SaasPlatformClient\Response\RawResponse;
+
+class RequestCacheInfoResolver implements CacheInfoResolver
+{
+
+    const DEFAULT_CACHE_TTL    = 86400; //24 hours
+    const CACHE_TTL_ONE_MINUTE = 60;
+
+    const OPTION_FS_SAAS_PLATFORM_VERSION_HASH = 'fs-saas-platform-version-hash';
+
+    /**
+     *
+     * @param Request $request
+     *
+     * @return bool
+     */
+    private function prepareCacheKey($request)
+    {
+        return md5($request->getEndpoint());
+    }
+
+    /**
+     *
+     * @param Request $request
+     *
+     * @return bool
+     */
+    public function isSupported($request)
+    {
+        if ($request instanceof BasicRequest) {
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     *
+     * @param Request $request
+     *
+     * @return bool
+     */
+    public function shouldCache($request)
+    {
+        if ($request instanceof ConnectKeyInfoRequest) {
+            return false;
+        }
+        if ($request instanceof GetStatusRequest) {
+            return false;
+        }
+        if ($request instanceof BasicRequest) {
+            if ('GET' === $request->getMethod()) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     *
+     * @param Request $request
+     *
+     * @return HowToCache
+     */
+    public function prepareHowToCache($request)
+    {
+        $howToCache = new HowToCache($this->prepareCacheKey($request), self::DEFAULT_CACHE_TTL);
+        return $howToCache;
+    }
+
+    /**
+     * @param ApiResponse $response
+     *
+     * @return bool
+     */
+    private function isPlatformVersionFromResponseChanged(ApiResponse $response)
+    {
+        $stored_hash = get_option(self::OPTION_FS_SAAS_PLATFORM_VERSION_HASH, '');
+        if ($stored_hash !== $response->getPlatformVersionHash()) {
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * @param ApiResponse $response
+     */
+    private function storePlatformVersionHashFromResponse(ApiResponse $response)
+    {
+        update_option(self::OPTION_FS_SAAS_PLATFORM_VERSION_HASH, $response->getPlatformVersionHash());
+    }
+
+    /**
+     *
+     * @param Request $request
+     * @param mixed $item
+     *
+     * @return bool
+     */
+    public function shouldClearCache($request, $item)
+    {
+        if ($request instanceof PutSettingsRequest) {
+            return true;
+        }
+        if ($item instanceof ApiResponse && $this->isPlatformVersionFromResponseChanged($item)) {
+            $this->storePlatformVersionHashFromResponse($item);
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     *
+     * @param Request $request
+     * @param mixed $item
+     *
+     * @return string[]
+     */
+    public function shouldClearKeys($request, $item)
+    {
+        if ('GET' !== $request->getMethod()) {
+            return [$this->prepareCacheKey($request)];
+        }
+        return [];
+    }
+
+
+}
\ No newline at end of file
diff --git a/src/Request/AuthRequest.php b/src/Request/AuthRequest.php
new file mode 100644
index 0000000000000000000000000000000000000000..34158128cd8aaa61a9bf8937795c9339dee68b88
--- /dev/null
+++ b/src/Request/AuthRequest.php
@@ -0,0 +1,53 @@
+<?php
+
+namespace WPDesk\SaasPlatformClient\Request;
+
+use WPDesk\SaasPlatformClient\Authentication\Token;
+
+class AuthRequest extends BasicRequest
+{
+    /** @var Token */
+    private $token;
+
+    public function __construct(Token $token)
+    {
+        $this->setToken($token);
+    }
+
+    /**
+     * @param Token $token
+     */
+    public function setToken(Token $token)
+    {
+        $this->token = $token;
+    }
+
+    /**
+     * @return bool
+     */
+    public function isTokenExpired()
+    {
+        return $this->token->isExpired();
+    }
+
+    /**
+     * @return bool
+     */
+    public function isTokenInvalid()
+    {
+        return !$this->token->isSignatureValid();
+    }
+
+    /**
+     * Returns array of http headers
+     *
+     * @return array
+     */
+    public function getHeaders()
+    {
+        $headers = array(
+            'Authorization' => $this->token->getAuthString()
+        );
+        return array_merge($headers, parent::getHeaders());
+    }
+}
\ No newline at end of file
diff --git a/src/Request/Authentication/ConnectKeyInfoRequest.php b/src/Request/Authentication/ConnectKeyInfoRequest.php
new file mode 100644
index 0000000000000000000000000000000000000000..fe611c6ee521791041f60562f16119349f41b243
--- /dev/null
+++ b/src/Request/Authentication/ConnectKeyInfoRequest.php
@@ -0,0 +1,28 @@
+<?php
+
+namespace WPDesk\SaasPlatformClient\Request\Authentication;
+
+use WPDesk\SaasPlatformClient\Authentication\Token;
+use WPDesk\SaasPlatformClient\Request\AuthRequest;
+
+final class ConnectKeyInfoRequest extends AuthRequest
+{
+    /** @var string */
+    protected $method = 'GET';
+
+    /** @var string */
+    protected $endPoint = '/connectkeyinfo/{connectKey}';
+
+
+    /**
+     * ConnectKeyInfoRequest constructor.
+     * @param $connectKey
+     * @param Token $token
+     */
+    public function __construct($connectKey, Token $token)
+    {
+        parent::__construct($token);
+
+        $this->endPoint = str_replace('{connectKey}', $connectKey, $this->endPoint);
+    }
+}
\ No newline at end of file
diff --git a/src/Request/Authentication/ConnectKeyResetRequest.php b/src/Request/Authentication/ConnectKeyResetRequest.php
new file mode 100644
index 0000000000000000000000000000000000000000..0c2cd8cd06c831173081c86b99f744bfda7b994e
--- /dev/null
+++ b/src/Request/Authentication/ConnectKeyResetRequest.php
@@ -0,0 +1,23 @@
+<?php
+
+namespace WPDesk\SaasPlatformClient\Request\Authentication;
+
+use WPDesk\SaasPlatformClient\Authentication\Token;
+use WPDesk\SaasPlatformClient\Request\AuthRequest;
+
+final class ConnectKeyResetRequest extends AuthRequest
+{
+    /** @var string */
+    protected $method = 'POST';
+
+    /** @var string */
+    protected $endPoint = '/users/{id}/connectKeyReset';
+
+
+    public function __construct($user_id, Token $token)
+    {
+        parent::__construct($token);
+
+        $this->endPoint = str_replace('{id}', $user_id, $this->endPoint);
+    }
+}
\ No newline at end of file
diff --git a/src/Request/Authentication/RegisterRequest.php b/src/Request/Authentication/RegisterRequest.php
new file mode 100644
index 0000000000000000000000000000000000000000..3a231d6335adaf5c2fb42166bec65ba5539db85d
--- /dev/null
+++ b/src/Request/Authentication/RegisterRequest.php
@@ -0,0 +1,29 @@
+<?php
+
+namespace WPDesk\SaasPlatformClient\Request\Authentication;
+
+use WPDesk\SaasPlatformClient\Request\BasicRequest;
+
+final class RegisterRequest extends BasicRequest
+{
+    /** @var string */
+    protected $method = 'POST';
+
+    /** @var string */
+    protected $endPoint = '/register';
+
+    /**
+     * RegisterRequest constructor.
+     * @param string $email
+     * @param string $domain
+     * @param string $locale
+     * @param ?string $admin_url
+     */
+    public function __construct($email, $domain, $locale, $admin_url = null)
+    {
+        $this->data = compact('email', 'domain', 'locale');
+        if ($admin_url !== null) {
+            $this->data['adminUrl'] = $admin_url;
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/Request/Authentication/TokenRequest.php b/src/Request/Authentication/TokenRequest.php
new file mode 100644
index 0000000000000000000000000000000000000000..289011bc75516763aa2b8639d6e3d3626284e8ea
--- /dev/null
+++ b/src/Request/Authentication/TokenRequest.php
@@ -0,0 +1,26 @@
+<?php
+
+namespace WPDesk\SaasPlatformClient\Request\Authentication;
+
+
+use WPDesk\SaasPlatformClient\Request\BasicRequest;
+
+final class TokenRequest extends BasicRequest
+{
+    /** @var string */
+    protected $method = 'POST';
+
+    /** @var string */
+    protected $endPoint = '/token';
+
+    /**
+     * TokenRequest constructor.
+     * @param string $connectKey
+     * @param string $domain
+     * @param string $locale
+     */
+    public function __construct($connectKey, $domain, $locale)
+    {
+        $this->data = compact(['connectKey', 'domain', 'locale']);
+    }
+}
\ No newline at end of file
diff --git a/src/Request/BasicRequest.php b/src/Request/BasicRequest.php
new file mode 100644
index 0000000000000000000000000000000000000000..c185d1eaf3be7b2d72e85e21997cb0e01a1d0194
--- /dev/null
+++ b/src/Request/BasicRequest.php
@@ -0,0 +1,54 @@
+<?php
+
+namespace WPDesk\SaasPlatformClient\Request;
+
+
+class BasicRequest implements Request
+{
+    /** @var string */
+    protected $method;
+
+    /** @var array */
+    protected $data;
+
+    /** @var string */
+    protected $endPoint;
+
+    /**
+     * @return string
+     */
+    public function getMethod()
+    {
+        return $this->method;
+    }
+
+    /**
+     * Return endpoint in format /[^/]+/
+     *
+     * @return string
+     */
+    public function getEndpoint()
+    {
+        return '/' . trim($this->endPoint, '/');
+    }
+
+    /**
+     * Returns array of http headers
+     *
+     * @return array
+     */
+    public function getHeaders()
+    {
+        return array();
+    }
+
+    /**
+     * Return unserialized request body as array
+     *
+     * @return array
+     */
+    public function getBody()
+    {
+        return $this->data;
+    }
+}
\ No newline at end of file
diff --git a/src/Request/Cancel/PostCancelRequest.php b/src/Request/Cancel/PostCancelRequest.php
new file mode 100644
index 0000000000000000000000000000000000000000..a780ee2f1300af6262227aa966b526838644ecc8
--- /dev/null
+++ b/src/Request/Cancel/PostCancelRequest.php
@@ -0,0 +1,39 @@
+<?php
+
+namespace WPDesk\SaasPlatformClient\Request\Cancel;
+
+use WPDesk\SaasPlatformClient\Authentication\Token;
+use WPDesk\SaasPlatformClient\Request\AuthRequest;
+
+final class PostCancelRequest extends AuthRequest
+{
+    /** @var string */
+    protected $method = 'POST';
+
+    /** @var string */
+    protected $endPoint = '/shops/{shop}/shipping_services/{service}/shipments/{shipment}/cancel';
+
+    /**
+     * PostShipmentRequest constructor.
+     * @param Token $token
+     * @param int $shippingServiceId
+     * @param int $shopId
+     * @param int $shipmentId
+     */
+    public function __construct(
+        Token $token,
+        $shippingServiceId,
+        $shopId,
+        $shipmentId
+    ) {
+        parent::__construct($token);
+
+        $this->endPoint = str_replace(
+            ['{shop}', '{service}', '{shipment}'],
+            [$shopId, $shippingServiceId, $shipmentId],
+            $this->endPoint
+        );
+
+        $this->data = [];
+    }
+}
\ No newline at end of file
diff --git a/src/Request/Fields/GetFieldsRequest.php b/src/Request/Fields/GetFieldsRequest.php
new file mode 100644
index 0000000000000000000000000000000000000000..2e5b881261d77eb62b97001a8cb9d764f7170425
--- /dev/null
+++ b/src/Request/Fields/GetFieldsRequest.php
@@ -0,0 +1,45 @@
+<?php
+
+namespace WPDesk\SaasPlatformClient\Request\Fields;
+
+use WPDesk\SaasPlatformClient\Authentication\Token;
+use WPDesk\SaasPlatformClient\Request\AuthRequest;
+
+final class GetFieldsRequest extends AuthRequest
+{
+    /** @var string */
+    protected $method = 'GET';
+
+    /** @var string */
+    protected $endPoint = '/shops/{shop}/shipping_services/{service}/dynamic_fields/{zone_targets}';
+
+    const ZONE_TARGETS_DELIMITER = ',';
+
+    /**
+     * @param array $zoneTargets
+     * @return string
+     */
+    private function serializeZoneTargets(array $zoneTargets)
+    {
+        return implode(self::ZONE_TARGETS_DELIMITER, $zoneTargets);
+    }
+
+    /**
+     * PostShipmentRequest constructor.
+     * @param Token $token
+     * @param int $shippingServiceId
+     * @param int $shopId
+     * @param string[] $zoneTargets
+     */
+    public function __construct(
+        Token $token,
+        $shippingServiceId,
+        $shopId,
+        array $zoneTargets
+    ) {
+        parent::__construct($token);
+
+        $this->endPoint = str_replace(['{shop}', '{service}', '{zone_targets}'],
+            [$shopId, $shippingServiceId, $this->serializeZoneTargets($zoneTargets)], $this->endPoint);
+    }
+}
\ No newline at end of file
diff --git a/src/Request/Label/PostLabelRequest.php b/src/Request/Label/PostLabelRequest.php
new file mode 100644
index 0000000000000000000000000000000000000000..e34dcd7409ea459080ad61f9e2f1395e1e992a43
--- /dev/null
+++ b/src/Request/Label/PostLabelRequest.php
@@ -0,0 +1,36 @@
+<?php
+
+namespace WPDesk\SaasPlatformClient\Request\Label;
+
+use WPDesk\SaasPlatformClient\Authentication\Token;
+use WPDesk\SaasPlatformClient\Request\AuthRequest;
+
+final class PostLabelRequest extends AuthRequest
+{
+    /** @var string */
+    protected $method = 'POST';
+
+    /** @var string */
+    protected $endPoint = '/shops/{shop}/shipping_services/{service}/shipments/{shipment}/labels';
+
+    /**
+     * PostShipmentRequest constructor.
+     * @param Token $token
+     * @param int $shippingServiceId
+     * @param int $shopId
+     * @param int $shipmentId
+     */
+    public function __construct(
+        Token $token,
+        $shippingServiceId,
+        $shopId,
+        $shipmentId
+    ) {
+        parent::__construct($token);
+
+        $this->endPoint = str_replace(['{shop}', '{service}', '{shipment}'], [$shopId, $shippingServiceId, $shipmentId],
+            $this->endPoint);
+
+        $this->data = [];
+    }
+}
\ No newline at end of file
diff --git a/src/Request/Rate/PostRateRequest.php b/src/Request/Rate/PostRateRequest.php
new file mode 100644
index 0000000000000000000000000000000000000000..5352104b930daffd9c6ef11b2ad0c8361874ad31
--- /dev/null
+++ b/src/Request/Rate/PostRateRequest.php
@@ -0,0 +1,36 @@
+<?php
+
+namespace WPDesk\SaasPlatformClient\Request\Rate;
+
+use WPDesk\SaasPlatformClient\Authentication\Token;
+use WPDesk\SaasPlatformClient\Model\Rate\RateRequest;
+use WPDesk\SaasPlatformClient\Request\AuthRequest;
+
+final class PostRateRequest extends AuthRequest
+{
+    /** @var string */
+    protected $method = 'POST';
+
+    /** @var string */
+    protected $endPoint = '/shops/{shop}/shipping_services/{service}/rates';
+
+    /**
+     * PostRateRequest constructor.
+     * @param Token $token
+     * @param int $shippingServiceId
+     * @param int $shopId
+     * @param RateRequest $request
+     */
+    public function __construct(
+        Token $token,
+        $shippingServiceId,
+        $shopId,
+        RateRequest $request
+    ) {
+        parent::__construct($token);
+
+        $this->endPoint = str_replace(['{shop}', '{service}'], [$shopId, $shippingServiceId], $this->endPoint);
+
+        $this->data = $request->toArray();
+    }
+}
\ No newline at end of file
diff --git a/src/Request/Request.php b/src/Request/Request.php
new file mode 100644
index 0000000000000000000000000000000000000000..2810176c85a98f131200366f45dc7260d69c761e
--- /dev/null
+++ b/src/Request/Request.php
@@ -0,0 +1,27 @@
+<?php
+
+namespace WPDesk\SaasPlatformClient\Request;
+
+
+interface Request
+{
+    /**
+     * @return string
+     */
+    public function getMethod();
+
+    /**
+     * @return array
+     */
+    public function getHeaders();
+
+    /**
+     * @return array
+     */
+    public function getBody();
+
+    /**
+     * @return string
+     */
+    public function getEndpoint();
+}
\ No newline at end of file
diff --git a/src/Request/Shipment/GetUserListShipmentRequest.php b/src/Request/Shipment/GetUserListShipmentRequest.php
new file mode 100644
index 0000000000000000000000000000000000000000..176c4ba0c605439fd66a6b7e766de81228db98f1
--- /dev/null
+++ b/src/Request/Shipment/GetUserListShipmentRequest.php
@@ -0,0 +1,27 @@
+<?php
+
+namespace WPDesk\SaasPlatformClient\Request\Shipment;
+
+use WPDesk\SaasPlatformClient\Authentication\Token;
+use WPDesk\SaasPlatformClient\Model\Shipment\ShipmentRequest;
+use WPDesk\SaasPlatformClient\Request\AuthRequest;
+
+final class GetUserListShipmentRequest extends AuthRequest
+{
+    /** @var string */
+    protected $method = 'GET';
+
+    /** @var string */
+    protected $endPoint = '/users/{id}/shipments';
+
+    /**
+     * GetListShipmentRequest constructor.
+     * @param Token $token
+     */
+    public function __construct($user_id, Token $token)
+{
+        parent::__construct($token);
+
+        $this->endPoint = str_replace('{id}', $user_id, $this->endPoint);
+    }
+}
\ No newline at end of file
diff --git a/src/Request/Shipment/PostShipmentRequest.php b/src/Request/Shipment/PostShipmentRequest.php
new file mode 100644
index 0000000000000000000000000000000000000000..091382736b8d0ad8ddc67baac6f0f3b8b9502de6
--- /dev/null
+++ b/src/Request/Shipment/PostShipmentRequest.php
@@ -0,0 +1,36 @@
+<?php
+
+namespace WPDesk\SaasPlatformClient\Request\Shipment;
+
+use WPDesk\SaasPlatformClient\Authentication\Token;
+use WPDesk\SaasPlatformClient\Model\Shipment\ShipmentRequest;
+use WPDesk\SaasPlatformClient\Request\AuthRequest;
+
+final class PostShipmentRequest extends AuthRequest
+{
+    /** @var string */
+    protected $method = 'POST';
+
+    /** @var string */
+    protected $endPoint = '/shops/{shop}/shipping_services/{service}/shipments';
+
+    /**
+     * PostShipmentRequest constructor.
+     * @param Token $token
+     * @param int $shippingServiceId
+     * @param int $shopId
+     * @param ShipmentRequest $request
+     */
+    public function __construct(
+        Token $token,
+        $shippingServiceId,
+        $shopId,
+        ShipmentRequest $request
+    ) {
+        parent::__construct($token);
+
+        $this->endPoint = str_replace(['{shop}', '{service}'], [$shopId, $shippingServiceId], $this->endPoint);
+
+        $this->data = $request->toArray();
+    }
+}
\ No newline at end of file
diff --git a/src/Request/ShippingPlan/PutShippingPlanRequest.php b/src/Request/ShippingPlan/PutShippingPlanRequest.php
new file mode 100644
index 0000000000000000000000000000000000000000..010e09d5c6384afda712a33a6f080b29d4cdb176
--- /dev/null
+++ b/src/Request/ShippingPlan/PutShippingPlanRequest.php
@@ -0,0 +1,30 @@
+<?php
+
+namespace WPDesk\SaasPlatformClient\Request\ShippingPlan;
+
+use WPDesk\SaasPlatformClient\Authentication\Token;
+use WPDesk\SaasPlatformClient\Model\ShippingPlan;
+use WPDesk\SaasPlatformClient\Request\AuthRequest;
+
+
+final class PutShippingPlanRequest extends AuthRequest
+{
+    /** @var string */
+    protected $method = 'PUT';
+
+    /** @var ShippingPlan */
+    private $plan;
+
+    /** @var string */
+    protected $endPoint = '/shipping_plans/{id}';
+
+    public function __construct(Token $token, ShippingPlan $plan)
+    {
+        parent::__construct($token);
+        $this->plan = $plan;
+
+        $this->data = $plan->toArray();
+
+        $this->endPoint = str_replace('{id}', $plan->getId(), $this->endPoint);
+    }
+}
\ No newline at end of file
diff --git a/src/Request/ShippingServices/GetListRequest.php b/src/Request/ShippingServices/GetListRequest.php
new file mode 100644
index 0000000000000000000000000000000000000000..e23bba67f94e87236a9dca220d67d7a84c67f01c
--- /dev/null
+++ b/src/Request/ShippingServices/GetListRequest.php
@@ -0,0 +1,14 @@
+<?php
+
+namespace WPDesk\SaasPlatformClient\Request\ShippingServices;
+
+use WPDesk\SaasPlatformClient\Request\AuthRequest;
+
+final class GetListRequest extends AuthRequest
+{
+    /** @var string */
+    protected $method = 'GET';
+
+    /** @var string */
+    protected $endPoint = '/shipping_services';
+}
\ No newline at end of file
diff --git a/src/Request/ShippingServices/GetServiceRequest.php b/src/Request/ShippingServices/GetServiceRequest.php
new file mode 100644
index 0000000000000000000000000000000000000000..91785ab7146c730e62f3f47cb5ba4961654faeed
--- /dev/null
+++ b/src/Request/ShippingServices/GetServiceRequest.php
@@ -0,0 +1,29 @@
+<?php
+
+namespace WPDesk\SaasPlatformClient\Request\ShippingServices;
+
+use WPDesk\SaasPlatformClient\Authentication\Token;
+use WPDesk\SaasPlatformClient\Request\AuthRequest;
+
+final class GetServiceRequest extends AuthRequest
+{
+    /** @var string */
+    protected $method = 'GET';
+
+    /** @var string */
+    protected $endPoint = '/shipping_services/{id}';
+
+    /**
+     * PutSettingsRequest constructor.
+     * @param Token $token
+     * @param int $shippingServiceId
+     */
+    public function __construct(
+        Token $token,
+        $shippingServiceId
+    ) {
+        parent::__construct($token);
+
+        $this->endPoint = str_replace('{id}', $shippingServiceId, $this->endPoint);
+    }
+}
\ No newline at end of file
diff --git a/src/Request/ShippingServicesSettings/GetSettingsRequest.php b/src/Request/ShippingServicesSettings/GetSettingsRequest.php
new file mode 100644
index 0000000000000000000000000000000000000000..9040b31971050be2815ed975019bf93ca6fd76ea
--- /dev/null
+++ b/src/Request/ShippingServicesSettings/GetSettingsRequest.php
@@ -0,0 +1,38 @@
+<?php
+
+namespace WPDesk\SaasPlatformClient\Request\ShippingServicesSettings;
+
+use WPDesk\SaasPlatformClient\Authentication\Token;
+use WPDesk\SaasPlatformClient\Model\ShippingServiceSetting;
+use WPDesk\SaasPlatformClient\Request\AuthRequest;
+use WPDesk\SaasPlatformClient\Request\Traits\SettingsItemRequestHelper;
+
+final class GetSettingsRequest extends AuthRequest
+{
+    use SettingsItemRequestHelper;
+
+    /** @var string */
+    protected $method = 'GET';
+
+    /** @var string */
+    protected $endPoint = '/shipping_services/settings/{id}';
+
+    /**
+     * PutSettingsRequest constructor.
+     * @param Token $token
+     * @param int $shippingServiceId
+     * @param int $shopId
+     * @param string $settingType
+     */
+    public function __construct(
+        Token $token,
+        $shippingServiceId,
+        $shopId,
+        $settingType = ShippingServiceSetting::TYPE_CONNECTION_SETTINGS
+    ) {
+        parent::__construct($token);
+
+        $params = $this->buildSettingsId($shippingServiceId, $shopId, $settingType);
+        $this->endPoint = str_replace('{id}', $params, $this->endPoint);
+    }
+}
\ No newline at end of file
diff --git a/src/Request/ShippingServicesSettings/PostSettingsRequest.php b/src/Request/ShippingServicesSettings/PostSettingsRequest.php
new file mode 100644
index 0000000000000000000000000000000000000000..20e9af30262c0b9e2c502e1b3c5dbe7fe26078eb
--- /dev/null
+++ b/src/Request/ShippingServicesSettings/PostSettingsRequest.php
@@ -0,0 +1,30 @@
+<?php
+
+namespace WPDesk\SaasPlatformClient\Request\ShippingServicesSettings;
+
+use WPDesk\SaasPlatformClient\Authentication\Token;
+use WPDesk\SaasPlatformClient\Model\ShippingServiceSetting;
+use WPDesk\SaasPlatformClient\Request\AuthRequest;
+use WPDesk\SaasPlatformClient\Request\Traits\SettingsItemRequestHelper;
+
+final class PostSettingsRequest extends AuthRequest
+{
+    use SettingsItemRequestHelper;
+
+    /** @var string */
+    protected $method = 'POST';
+
+    /** @var ShippingServiceSetting */
+    private $setting;
+
+    /** @var string */
+    protected $endPoint = '/shipping_services/settings';
+
+    public function __construct(Token $token, ShippingServiceSetting $setting)
+    {
+        parent::__construct($token);
+        $this->setting = $setting;
+
+        $this->data = $setting->toArray();
+    }
+}
\ No newline at end of file
diff --git a/src/Request/ShippingServicesSettings/PutSettingsRequest.php b/src/Request/ShippingServicesSettings/PutSettingsRequest.php
new file mode 100644
index 0000000000000000000000000000000000000000..ea6079381b4d69d8681003edce5b7a46c603f5f7
--- /dev/null
+++ b/src/Request/ShippingServicesSettings/PutSettingsRequest.php
@@ -0,0 +1,36 @@
+<?php
+
+namespace WPDesk\SaasPlatformClient\Request\ShippingServicesSettings;
+
+use WPDesk\SaasPlatformClient\Authentication\Token;
+use WPDesk\SaasPlatformClient\Model\ShippingServiceSetting;
+use WPDesk\SaasPlatformClient\Request\AuthRequest;
+use WPDesk\SaasPlatformClient\Request\Traits\SettingsItemRequestHelper;
+
+final class PutSettingsRequest extends AuthRequest
+{
+    use SettingsItemRequestHelper;
+
+    /** @var string */
+    protected $method = 'PUT';
+
+    /** @var string */
+    protected $endPoint = '/shipping_services/settings/{id}';
+
+    /**
+     * PutSettingsRequest constructor.
+     * @param Token $token
+     * @param int $shippingServiceId
+     * @param int $shopId
+     * @param string $settingType
+     */
+    public function __construct(Token $token, ShippingServiceSetting $setting)
+    {
+        parent::__construct($token);
+
+        $params = $this->buildSettingsId($setting->getShippingService(), $setting->getShop(), $setting->getType());
+        $this->endPoint = str_replace('{id}', $params, $this->endPoint);
+
+        $this->data = $setting->toArray();
+    }
+}
\ No newline at end of file
diff --git a/src/Request/ShippingServicesSettings/Test/GetSettingsTestRequest.php b/src/Request/ShippingServicesSettings/Test/GetSettingsTestRequest.php
new file mode 100644
index 0000000000000000000000000000000000000000..45009ad1d99ce48a838403af57e2b72644cb9e5c
--- /dev/null
+++ b/src/Request/ShippingServicesSettings/Test/GetSettingsTestRequest.php
@@ -0,0 +1,37 @@
+<?php
+
+namespace WPDesk\SaasPlatformClient\Request\ShippingServicesSettings\Test;
+
+use WPDesk\SaasPlatformClient\Authentication\Token;
+use WPDesk\SaasPlatformClient\Model\ShippingServiceSetting;
+use WPDesk\SaasPlatformClient\Request\AuthRequest;
+
+final class GetSettingsTestRequest extends AuthRequest
+{
+    /** @var string */
+    protected $method = 'GET';
+
+    /** @var string */
+    protected $endPoint = '/shops/{shop}/shipping_services/{service}/settings/{type}/test';
+
+    /**
+     * PutSettingsRequest constructor.
+     * @param Token $token
+     * @param int $shippingServiceId
+     * @param int $shopId
+     */
+    public function __construct(
+        Token $token,
+        $shippingServiceId,
+        $shopId
+    ) {
+        parent::__construct($token);
+
+        $this->endPoint = str_replace(
+            ['{shop}', '{service}', '{type}'],
+            [$shopId, $shippingServiceId, ShippingServiceSetting::TYPE_CONNECTION_SETTINGS],
+            $this->endPoint
+        );
+    }
+
+}
\ No newline at end of file
diff --git a/src/Request/Status/GetStatusRequest.php b/src/Request/Status/GetStatusRequest.php
new file mode 100644
index 0000000000000000000000000000000000000000..59b9a17aa78f7869f4afb185082ac46b3c7058ec
--- /dev/null
+++ b/src/Request/Status/GetStatusRequest.php
@@ -0,0 +1,49 @@
+<?php
+
+namespace WPDesk\SaasPlatformClient\Request\Status;
+
+use WPDesk\SaasPlatformClient\Authentication\Token;
+use WPDesk\SaasPlatformClient\Request\AuthRequest;
+use WPDesk\SaasPlatformClient\Request\BasicRequest;
+
+final class GetStatusRequest extends BasicRequest
+{
+
+    /** @var string */
+    protected $method = 'GET';
+
+    /** @var string */
+    protected $endPoint = '/status';
+
+    /** @var Token */
+    private $token;
+
+    /**
+     * GetStatusRequest constructor.
+     *
+     * @param null|Token $token
+     */
+    public function __construct(
+        Token $token = null
+    ) {
+        $this->token = $token;
+    }
+
+    /**
+     * Returns array of http headers
+     *
+     * @return array
+     */
+    public function getHeaders()
+    {
+        if (null !== $this->token) {
+            $headers = array(
+                'Authorization' => $this->token->getAuthString()
+            );
+            return array_merge($headers, parent::getHeaders());
+        } else {
+            return parent::getHeaders();
+        }
+    }
+
+}
\ No newline at end of file
diff --git a/src/Request/Traits/SettingsItemRequestHelper.php b/src/Request/Traits/SettingsItemRequestHelper.php
new file mode 100644
index 0000000000000000000000000000000000000000..9b97fad8a479addfcf4e1d8e6df85376475d9745
--- /dev/null
+++ b/src/Request/Traits/SettingsItemRequestHelper.php
@@ -0,0 +1,28 @@
+<?php
+
+namespace WPDesk\SaasPlatformClient\Request\Traits;
+
+trait SettingsItemRequestHelper
+{
+
+    /**
+     * Build multiple compound key id in api-platform
+     *
+     * @param int $shippingServiceId
+     * @param int $shopId
+     * @param string|null $settingType
+     * @return string
+     */
+    private function buildSettingsId($shippingServiceId, $shopId, $settingType = null)
+    {
+        $query_data = [
+            'shippingService' => $shippingServiceId,
+            'shop' => $shopId,
+            'type' => $settingType
+        ];
+        if (null !== $settingType) {
+            $query_data['type'] = $settingType;
+        }
+        return http_build_query($query_data, null, ';');
+    }
+}
\ No newline at end of file
diff --git a/src/Request/Users/GetUserRequest.php b/src/Request/Users/GetUserRequest.php
new file mode 100644
index 0000000000000000000000000000000000000000..62b0c7a428e9b7000163780a56ed740de1e1d080
--- /dev/null
+++ b/src/Request/Users/GetUserRequest.php
@@ -0,0 +1,28 @@
+<?php
+
+namespace WPDesk\SaasPlatformClient\Request\Users;
+
+use WPDesk\SaasPlatformClient\Authentication\Token;
+use WPDesk\SaasPlatformClient\Request\AuthRequest;
+
+final class GetUserRequest extends AuthRequest
+{
+    /** @var string */
+    protected $method = 'GET';
+
+    /** @var string */
+    protected $endPoint = '/users/{id}';
+
+    /**
+     * getUserRequest constructor.
+     *
+     * @param $user_id
+     * @param Token $token
+     */
+    public function __construct($user_id, Token $token)
+    {
+        parent::__construct($token);
+
+        $this->endPoint = str_replace('{id}', $user_id, $this->endPoint);
+    }
+}
\ No newline at end of file
diff --git a/src/Response/ApiResponse.php b/src/Response/ApiResponse.php
new file mode 100644
index 0000000000000000000000000000000000000000..486e321e6cfb4684524a6745bae53fa7d44a572a
--- /dev/null
+++ b/src/Response/ApiResponse.php
@@ -0,0 +1,35 @@
+<?php
+
+namespace WPDesk\SaasPlatformClient\Response;
+
+
+interface ApiResponse extends Response
+{
+    /**
+     * Get links structure to the other request
+     *
+     * @return array
+     */
+    public function getLinks();
+
+    /**
+     * Is it a BAD REQUEST response
+     *
+     * @return bool
+     */
+    public function isBadRequest();
+
+    /**
+     * Is it a FATAL ERROR response
+     *
+     * @return bool
+     */
+    public function isServerFatalError();
+
+    /**
+     * Is requested resource exists
+     *
+     * @return bool
+     */
+    public function isNotExists();
+}
\ No newline at end of file
diff --git a/src/Response/AuthApiResponse.php b/src/Response/AuthApiResponse.php
new file mode 100644
index 0000000000000000000000000000000000000000..05fee1449be1b4ac66f0b5e15754b6da4acf5688
--- /dev/null
+++ b/src/Response/AuthApiResponse.php
@@ -0,0 +1,14 @@
+<?php
+
+namespace WPDesk\SaasPlatformClient\Response;
+
+use WPDesk\SaasPlatformClient\Response\Traits\AuthApiResponseDecorator;
+
+class AuthApiResponse implements ApiResponse
+{
+    const RESPONSE_CODE_BAD_CREDENTIALS = 401;
+
+    const RESPONSE_CODE_NOT_EXISTS = 404;
+
+    use AuthApiResponseDecorator;
+}
\ No newline at end of file
diff --git a/src/Response/Authentication/ConnectKeyInfoResponse.php b/src/Response/Authentication/ConnectKeyInfoResponse.php
new file mode 100644
index 0000000000000000000000000000000000000000..d89aba812184796b8fd24d1ccb61c693749a18f1
--- /dev/null
+++ b/src/Response/Authentication/ConnectKeyInfoResponse.php
@@ -0,0 +1,37 @@
+<?php
+
+namespace WPDesk\SaasPlatformClient\Response\Authentication;
+
+use WPDesk\SaasPlatformClient\Response\ApiResponse;
+use WPDesk\SaasPlatformClient\Response\Traits\ApiResponseDecorator;
+
+final class ConnectKeyInfoResponse implements ApiResponse
+{
+    use ApiResponseDecorator;
+
+    /**
+     * @return int
+     */
+    public function getUserId()
+    {
+        return (int)$this->getResponseBody()['owner_id'];
+    }
+
+    /**
+     * @return \DateTimeImmutable
+     * @throws \Exception
+     */
+    public function getLastUsed()
+    {
+        $lastUsed = $this->getResponseBody()['lastUsed'];
+        return new \DateTimeImmutable($lastUsed['date']);
+    }
+
+    /**
+     * @return array[string]
+     */
+    public function getDomains()
+    {
+        return $this->getResponseBody()['domains'];
+    }
+}
\ No newline at end of file
diff --git a/src/Response/Authentication/ConnectKeyResetResponse.php b/src/Response/Authentication/ConnectKeyResetResponse.php
new file mode 100644
index 0000000000000000000000000000000000000000..4f78a305d26bfbfd9494a42108b214964495cb84
--- /dev/null
+++ b/src/Response/Authentication/ConnectKeyResetResponse.php
@@ -0,0 +1,22 @@
+<?php
+
+namespace WPDesk\SaasPlatformClient\Response\Authentication;
+
+use WPDesk\SaasPlatformClient\Response\ApiResponse;
+use WPDesk\SaasPlatformClient\Response\Traits\AuthApiResponseDecorator;
+
+final class ConnectKeyResetResponse implements ApiResponse
+{
+    use AuthApiResponseDecorator;
+
+    /**
+     * Returns newly generated connect key
+     *
+     * @return string
+     */
+    public function getNewConnectKey()
+    {
+        $body = $this->getResponseBody();
+        return (string)$body['connectKey'];
+    }
+}
\ No newline at end of file
diff --git a/src/Response/Authentication/RegisterResponse.php b/src/Response/Authentication/RegisterResponse.php
new file mode 100644
index 0000000000000000000000000000000000000000..046a70f7d699b4b8f768d50d02253770741b159a
--- /dev/null
+++ b/src/Response/Authentication/RegisterResponse.php
@@ -0,0 +1,59 @@
+<?php
+
+namespace WPDesk\SaasPlatformClient\Response\Authentication;
+
+use WPDesk\SaasPlatformClient\Response\ApiResponse;
+use WPDesk\SaasPlatformClient\Response\RawResponse;
+use WPDesk\SaasPlatformClient\Response\Traits\ApiResponseDecorator;
+
+final class RegisterResponse implements ApiResponse
+{
+    const API_KEY_FIELD = 'password';
+
+    const RESPONSE_CODE_USER_ALREADY_EXISTS = 460;
+
+    const RESPONSE_CODE_DOMAIN_ALREADY_EXISTS = 461;
+
+    use ApiResponseDecorator;
+
+    /**
+     * Returns true if user is registered
+     *
+     * @return bool
+     */
+    public function isUserRegistered()
+    {
+        return in_array($this->getResponseCode(),
+            [RawResponse::RESPONSE_CODE_CREATED, RawResponse::RESPONSE_CODE_SUCCESS]);
+    }
+
+    /**
+     * Returns true if user is was already registered
+     *
+     * @return bool
+     */
+    public function isUserAlreadyExists()
+    {
+        return $this->getResponseCode() === self::RESPONSE_CODE_USER_ALREADY_EXISTS;
+    }
+
+    /**
+     * Returns true if user cannot be registered because domain is occupied
+     *
+     * @return bool
+     */
+    public function isDomainOccupied()
+    {
+        return $this->getResponseCode() === self::RESPONSE_CODE_DOMAIN_ALREADY_EXISTS;
+    }
+
+    /**
+     * Returns apiKey from register response
+     *
+     * @return string
+     */
+    public function getApiKey()
+    {
+        return $this->getResponseBody()[self::API_KEY_FIELD];
+    }
+}
\ No newline at end of file
diff --git a/src/Response/Authentication/TokenResponse.php b/src/Response/Authentication/TokenResponse.php
new file mode 100644
index 0000000000000000000000000000000000000000..e7a724777482bc0bc11982e361b9cc125a088353
--- /dev/null
+++ b/src/Response/Authentication/TokenResponse.php
@@ -0,0 +1,56 @@
+<?php
+
+namespace WPDesk\SaasPlatformClient\Response\Authentication;
+
+use WPDesk\SaasPlatformClient\Authentication\JWTToken;
+use WPDesk\SaasPlatformClient\Response\ApiResponse;
+use WPDesk\SaasPlatformClient\Response\AuthApiResponse;
+use WPDesk\SaasPlatformClient\Response\Traits\ApiResponseDecorator;
+
+final class TokenResponse implements ApiResponse
+{
+    use ApiResponseDecorator;
+
+    const RESPONSE_CODE_LOGIN_SUCCESS = 200;
+
+    /**
+     * Returns token if exists
+     *
+     * @return JWTToken
+     */
+    public function getToken()
+    {
+        $body = $this->getResponseBody();
+        return new JWTToken($body['token']);
+    }
+
+    /**
+     * @return bool
+     */
+    public function isBadCredentials()
+    {
+        return $this->getResponseCode() === AuthApiResponse::RESPONSE_CODE_BAD_CREDENTIALS;
+    }
+
+    /**
+     * Returns true if login is a success and token is available
+     *
+     * @return bool
+     */
+    public function isLoginSuccess()
+    {
+        return $this->getResponseCode() === self::RESPONSE_CODE_LOGIN_SUCCESS;
+    }
+
+    /**
+     * Returns true if user cannot be registered because domain is occupied
+     *
+     * @return bool
+     */
+    public function isDomainOccupied()
+    {
+        return $this->getResponseCode() === RegisterResponse::RESPONSE_CODE_DOMAIN_ALREADY_EXISTS;
+    }
+
+
+}
\ No newline at end of file
diff --git a/src/Response/Cancel/PostCancelResponse.php b/src/Response/Cancel/PostCancelResponse.php
new file mode 100644
index 0000000000000000000000000000000000000000..091c61051f1e82d7abe2eb2fb65a5fa171364d1c
--- /dev/null
+++ b/src/Response/Cancel/PostCancelResponse.php
@@ -0,0 +1,11 @@
+<?php
+
+namespace WPDesk\SaasPlatformClient\Response\Cancel;
+
+use WPDesk\SaasPlatformClient\Response\ApiResponse;
+use WPDesk\SaasPlatformClient\Response\Traits\AuthApiResponseDecorator;
+
+class PostCancelResponse implements ApiResponse
+{
+    use AuthApiResponseDecorator;
+}
diff --git a/src/Response/Exception/EmptyMessageFromResponse.php b/src/Response/Exception/EmptyMessageFromResponse.php
new file mode 100644
index 0000000000000000000000000000000000000000..870a00cbf47c12699b699ffb4843c5ebcf4b6d96
--- /dev/null
+++ b/src/Response/Exception/EmptyMessageFromResponse.php
@@ -0,0 +1,19 @@
+<?php
+
+namespace WPDesk\SaasPlatformClient\Response\Exception;
+
+class EmptyMessageFromResponse extends \RuntimeException
+{
+    /**
+     * Exception factory
+     *
+     * @param string $request
+     * @param int $errorCode
+     * @return TriedExtractDataFromErrorResponse
+     */
+    public static function createWithClassInfo($request, $errorCode)
+    {
+        return new EmptyStatusFromResponse("Tried to extract message from {$request} when an error occured. Response code: {$errorCode}",
+            $errorCode);
+    }
+}
\ No newline at end of file
diff --git a/src/Response/Exception/EmptyStatusFromResponse.php b/src/Response/Exception/EmptyStatusFromResponse.php
new file mode 100644
index 0000000000000000000000000000000000000000..a077eca3145a4239826cac9c444fa423f2e3af4b
--- /dev/null
+++ b/src/Response/Exception/EmptyStatusFromResponse.php
@@ -0,0 +1,19 @@
+<?php
+
+namespace WPDesk\SaasPlatformClient\Response\Exception;
+
+class EmptyStatusFromResponse extends \RuntimeException
+{
+    /**
+     * Exception factory
+     *
+     * @param string $request
+     * @param int $errorCode
+     * @return TriedExtractDataFromErrorResponse
+     */
+    public static function createWithClassInfo($request, $errorCode)
+    {
+        return new EmptyStatusFromResponse("Tried to extract status from {$request} when an error occured. Response code: {$errorCode}",
+            $errorCode);
+    }
+}
\ No newline at end of file
diff --git a/src/Response/Exception/TriedExtractDataFromErrorResponse.php b/src/Response/Exception/TriedExtractDataFromErrorResponse.php
new file mode 100644
index 0000000000000000000000000000000000000000..38d21ffd6ebdd81e72907e9cc3dd0aaf2bbb6405
--- /dev/null
+++ b/src/Response/Exception/TriedExtractDataFromErrorResponse.php
@@ -0,0 +1,19 @@
+<?php
+
+namespace WPDesk\SaasPlatformClient\Response\Exception;
+
+class TriedExtractDataFromErrorResponse extends \RuntimeException
+{
+    /**
+     * Exception factory
+     *
+     * @param string $request
+     * @param int $errorCode
+     * @return TriedExtractDataFromErrorResponse
+     */
+    public static function createWithClassInfo($request, $errorCode)
+    {
+        return new TriedExtractDataFromErrorResponse("Tried to extract data from {$request} when an error occured. Response code: {$errorCode}",
+            $errorCode);
+    }
+}
\ No newline at end of file
diff --git a/src/Response/Fields/GetFieldsResponse.php b/src/Response/Fields/GetFieldsResponse.php
new file mode 100644
index 0000000000000000000000000000000000000000..710e5e68297bed31b98bcf88bfdfaf86ec47c43e
--- /dev/null
+++ b/src/Response/Fields/GetFieldsResponse.php
@@ -0,0 +1,19 @@
+<?php
+
+namespace WPDesk\SaasPlatformClient\Response\Fields;
+
+use WPDesk\SaasPlatformClient\Response\ApiResponse;
+use WPDesk\SaasPlatformClient\Response\Traits\AuthApiResponseDecorator;
+
+class GetFieldsResponse implements ApiResponse
+{
+    use AuthApiResponseDecorator;
+
+    /**
+     * @return array
+     */
+    public function getFields()
+    {
+        return $this->getResponseBody()['fieldsJson'];
+    }
+}
diff --git a/src/Response/Label/PostLabelResponse.php b/src/Response/Label/PostLabelResponse.php
new file mode 100644
index 0000000000000000000000000000000000000000..83f598553766ade50ef95a56079463f1dbb01e8b
--- /dev/null
+++ b/src/Response/Label/PostLabelResponse.php
@@ -0,0 +1,20 @@
+<?php
+
+namespace WPDesk\SaasPlatformClient\Response\Label;
+
+use WPDesk\SaasPlatformClient\Model\Label\Label;
+use WPDesk\SaasPlatformClient\Response\ApiResponse;
+use WPDesk\SaasPlatformClient\Response\Traits\AuthApiResponseDecorator;
+
+class PostLabelResponse implements ApiResponse
+{
+    use AuthApiResponseDecorator;
+
+    /**
+     * @return Label
+     */
+    public function getLabel()
+    {
+        return new Label($this->getResponseBody());
+    }
+}
diff --git a/src/Response/Maintenance/MaintenanceResponseContext.php b/src/Response/Maintenance/MaintenanceResponseContext.php
new file mode 100644
index 0000000000000000000000000000000000000000..fa0a0661be3f807d04a6c23acb9606fcf108d1cc
--- /dev/null
+++ b/src/Response/Maintenance/MaintenanceResponseContext.php
@@ -0,0 +1,50 @@
+<?php
+
+namespace WPDesk\SaasPlatformClient\Response\Maintenance;
+
+use WPDesk\SaasPlatformClient\Response\Response;
+
+class MaintenanceResponseContext
+{
+
+    /**
+     * Response.
+     *
+     * @var Response
+     */
+    private $response;
+
+    public function __construct(Response $response)
+    {
+        $this->response = $response;
+    }
+
+    /**
+     * Get maintenance message.
+     *
+     * @return string|null
+     */
+    public function getMaintenanceMessage()
+    {
+        $responseBody = $this->response->getResponseBody();
+        if (isset($responseBody['message'])) {
+            return $responseBody['message'];
+        }
+        return null;
+    }
+
+    /**
+     * Get maintenance till.
+     *
+     * @return int|null
+     */
+    public function getMaintenanceTill()
+    {
+        $responseBody = $this->response->getResponseBody();
+        if (isset($responseBody['maintenance_till'])) {
+            return intval($responseBody['maintenance_till']);
+        }
+        return null;
+    }
+
+}
\ No newline at end of file
diff --git a/src/Response/ProtectedResponse.php b/src/Response/ProtectedResponse.php
new file mode 100644
index 0000000000000000000000000000000000000000..363fde03ebe500ef094bd7fbafec10c3b8ae85e9
--- /dev/null
+++ b/src/Response/ProtectedResponse.php
@@ -0,0 +1,27 @@
+<?php
+
+namespace WPDesk\SaasPlatformClient\Response;
+
+use WPDesk\SaasPlatformClient\Response\Exception\TriedExtractDataFromErrorResponse;
+use WPDesk\SaasPlatformClient\Response\Traits\ApiResponseDecorator;
+
+/**
+ * Response is protected in a way so when you try to get body of the response when an error occured you will get an exception
+ *
+ * Class ProtectedResponse
+ * @package WPDesk\SaasPlatformClient\Response
+ */
+class ProtectedResponse implements Response
+{
+    use ApiResponseDecorator;
+
+    public function getResponseBody()
+    {
+        if ($this->isError()) {
+            throw TriedExtractDataFromErrorResponse::createWithClassInfo(get_class($this->rawResponse), $this->getResponseCode());
+        }
+        return $this->rawResponse->getResponseBody();
+    }
+
+
+}
\ No newline at end of file
diff --git a/src/Response/Rate/PostRateResponse.php b/src/Response/Rate/PostRateResponse.php
new file mode 100644
index 0000000000000000000000000000000000000000..8f53e7e3a0389343f48f404195de193a5dc20dc8
--- /dev/null
+++ b/src/Response/Rate/PostRateResponse.php
@@ -0,0 +1,31 @@
+<?php
+
+namespace WPDesk\SaasPlatformClient\Response\Rate;
+
+use WPDesk\SaasPlatformClient\Model\Rate\RateResponse;
+use WPDesk\SaasPlatformClient\Response\ApiResponse;
+use WPDesk\SaasPlatformClient\Response\Traits\AuthApiResponseDecorator;
+
+class PostRateResponse implements ApiResponse
+{
+    use AuthApiResponseDecorator;
+
+    const RESPONSE_CODE_RATE_FAILED = 274;
+
+    /**
+     * @return RateResponse
+     */
+    public function getRate()
+    {
+        return new RateResponse($this->getResponseBody());
+    }
+
+    /**
+     * Platform can't respond in meaningful way about rates
+     *
+     * @return bool
+     */
+    public function isRateFailedError() {
+        return $this->rawResponse->getResponseCode() === self::RESPONSE_CODE_RATE_FAILED;
+    }
+}
diff --git a/src/Response/RawResponse.php b/src/Response/RawResponse.php
new file mode 100644
index 0000000000000000000000000000000000000000..6360d2e2d8a7efb7617ddce3ce2e7b84395c1dd1
--- /dev/null
+++ b/src/Response/RawResponse.php
@@ -0,0 +1,113 @@
+<?php
+
+namespace WPDesk\SaasPlatformClient\Response;
+
+class RawResponse implements Response
+{
+    const RESPONSE_CODE_SUCCESS = 200;
+    const RESPONSE_CODE_CREATED = 201;
+    const RESPONSE_CODE_ERROR_BAD_REQUEST = 400;
+    const RESPONSE_CODE_DOMAIN_NOT_ALLOWED = 462;
+    const RESPONSE_CODE_ERROR_FATAL = 500;
+    const RESPONSE_CODE_MAINTENANCE = 503;
+    const HEADER_X_PLATFORM_VERSION_HASH = 'X-Platform-Version-Hash';
+
+    /** @var array */
+    private $data;
+
+    /** @var int */
+    private $code;
+
+    /** @var array */
+    private $headers;
+
+    /**
+     * RawResponse constructor.
+     * @param array $body
+     * @param int $code
+     * @param array $headers
+     */
+    public function __construct(array $body, $code, array $headers)
+    {
+        $this->data = $body;
+        $this->code = (int)$code;
+        $this->headers = $headers;
+    }
+
+    /**
+     * Returns response http code
+     *
+     * @return int
+     */
+    public function getResponseCode()
+    {
+        return $this->code;
+    }
+
+    /**
+     * Returns response body as array
+     *
+     * @return array
+     */
+    public function getResponseBody()
+    {
+        return $this->data;
+    }
+
+    /**
+     * Returns response body as array
+     *
+     * @return array
+     */
+    public function getResponseErrorBody()
+    {
+        return $this->data;
+    }
+
+    /**
+     * Returns response body as array
+     *
+     * @return array
+     */
+    public function getResponseHeaders()
+    {
+        return $this->headers;
+    }
+
+    /**
+     * Is any error occured
+     *
+     * @return bool
+     */
+    public function isError()
+    {
+        $code = $this->getResponseCode();
+        return ( $code < 200 || $code >= 300 ) && !$this->isMaintenance();
+    }
+
+    /**
+     * Is maintenance.
+     *
+     * @return bool
+     */
+    public function isMaintenance()
+    {
+        $code = $this->getResponseCode();
+        return self::RESPONSE_CODE_MAINTENANCE === $code;
+    }
+
+    /**
+     * Get platform version hash string.
+     *
+     * @return bool|string
+     */
+    public function getPlatformVersionHash()
+    {
+        if (isset($this->headers[self::HEADER_X_PLATFORM_VERSION_HASH])) {
+            return $this->headers[self::HEADER_X_PLATFORM_VERSION_HASH];
+        }
+        return false;
+    }
+
+
+}
\ No newline at end of file
diff --git a/src/Response/Response.php b/src/Response/Response.php
new file mode 100644
index 0000000000000000000000000000000000000000..245bfc4158f5021b67cdd6bd572ae6b62ab0cd5e
--- /dev/null
+++ b/src/Response/Response.php
@@ -0,0 +1,43 @@
+<?php
+
+namespace WPDesk\SaasPlatformClient\Response;
+
+
+interface Response
+{
+    /**
+     * @return int
+     */
+    public function getResponseCode();
+
+    /** @return array */
+    public function getResponseBody();
+
+    /** @return array */
+    public function getResponseHeaders();
+
+    /** @return array */
+    public function getResponseErrorBody();
+
+    /**
+     * Is any error occured
+     *
+     * @return bool
+     */
+    public function isError();
+
+    /**
+     * Is maintenance
+     *
+     * @return bool
+     */
+    public function isMaintenance();
+
+    /**
+     * Get platform version hash string.
+     *
+     * @return bool|string
+     */
+    public function getPlatformVersionHash();
+
+}
\ No newline at end of file
diff --git a/src/Response/Shipment/GetListShipmentAdminContextResponse.php b/src/Response/Shipment/GetListShipmentAdminContextResponse.php
new file mode 100644
index 0000000000000000000000000000000000000000..3aa1bd03fbaaeefc73e7e1830ad85a165ec4e3ea
--- /dev/null
+++ b/src/Response/Shipment/GetListShipmentAdminContextResponse.php
@@ -0,0 +1,29 @@
+<?php
+
+namespace WPDesk\SaasPlatformClient\Response\Shipment;
+
+use WPDesk\SaasPlatformClient\Model\Shipment\ShipmentAdminContext;
+use WPDesk\SaasPlatformClient\Response\ApiResponse;
+use WPDesk\SaasPlatformClient\Response\Traits\AuthApiResponseDecorator;
+use WPDesk\SaasPlatformClient\Response\Traits\PagedListImplementation;
+
+class GetListShipmentAdminContextResponse implements ApiResponse
+{
+    use AuthApiResponseDecorator;
+    use PagedListImplementation;
+
+    /*
+     * @return ShippingService[]
+     */
+    public function getPage()
+    {
+        $page = $this->getRawPage();
+        $itemList = [];
+        if (count($page) > 0) {
+            foreach ($page as $item) {
+                $itemList[] = new ShipmentAdminContext($item);
+            }
+        }
+        return $itemList;
+    }
+}
\ No newline at end of file
diff --git a/src/Response/Shipment/PostShipmentResponse.php b/src/Response/Shipment/PostShipmentResponse.php
new file mode 100644
index 0000000000000000000000000000000000000000..1153fff015538a8aec6958040dc74a03ec6191e2
--- /dev/null
+++ b/src/Response/Shipment/PostShipmentResponse.php
@@ -0,0 +1,30 @@
+<?php
+
+namespace WPDesk\SaasPlatformClient\Response\Shipment;
+
+use WPDesk\SaasPlatformClient\Model\Shipment\ShipmentResponse;
+use WPDesk\SaasPlatformClient\Response\ApiResponse;
+use WPDesk\SaasPlatformClient\Response\Traits\AuthApiResponseDecorator;
+
+class PostShipmentResponse implements ApiResponse
+{
+    use AuthApiResponseDecorator;
+
+    const RESPONSE_CODE_SHIPMENT_PLAN_EXCEEDED = 472;
+
+    /**
+     * @return bool
+     */
+    public function isShipmentPlanExceeded()
+    {
+        return $this->getResponseCode() === self::RESPONSE_CODE_SHIPMENT_PLAN_EXCEEDED;
+    }
+
+    /**
+     * @return ShipmentResponse
+     */
+    public function getShipment()
+    {
+        return new ShipmentResponse($this->getResponseBody());
+    }
+}
diff --git a/src/Response/ShippingServices/GetShippingServiceResponse.php b/src/Response/ShippingServices/GetShippingServiceResponse.php
new file mode 100644
index 0000000000000000000000000000000000000000..3ea05c4b2a66966d19e2514f649c05b499b02e7a
--- /dev/null
+++ b/src/Response/ShippingServices/GetShippingServiceResponse.php
@@ -0,0 +1,20 @@
+<?php
+
+namespace WPDesk\SaasPlatformClient\Response\ShippingServices;
+
+use WPDesk\SaasPlatformClient\Model\ShippingService;
+use WPDesk\SaasPlatformClient\Response\ApiResponse;
+use WPDesk\SaasPlatformClient\Response\Traits\AuthApiResponseDecorator;
+
+final class GetShippingServiceResponse implements ApiResponse
+{
+    use AuthApiResponseDecorator;
+
+    /**
+     * @return ShippingService
+     */
+    public function getShippingService()
+    {
+        return new ShippingService($this->getResponseBody());
+    }
+}
\ No newline at end of file
diff --git a/src/Response/ShippingServices/GetShippingServicesListResponse.php b/src/Response/ShippingServices/GetShippingServicesListResponse.php
new file mode 100644
index 0000000000000000000000000000000000000000..fc89bbfee1f9c131c629786817dd39745ae723f2
--- /dev/null
+++ b/src/Response/ShippingServices/GetShippingServicesListResponse.php
@@ -0,0 +1,30 @@
+<?php
+
+namespace WPDesk\SaasPlatformClient\Response\ShippingServices;
+
+use WPDesk\SaasPlatformClient\Model\ShippingService;
+use WPDesk\SaasPlatformClient\Response\ApiResponse;
+use WPDesk\SaasPlatformClient\Response\Traits\AuthApiResponseDecorator;
+use WPDesk\SaasPlatformClient\Response\Traits\PagedListImplementation;
+
+final class GetShippingServicesListResponse implements ApiResponse
+{
+    use AuthApiResponseDecorator;
+    use PagedListImplementation;
+
+    /*
+     * @return ShippingService[]
+     */
+    public function getPage()
+    {
+        $page = $this->getRawPage();
+        $itemList = [];
+        if (count($page) > 0) {
+            foreach ($page as $item) {
+                $itemList[] = new ShippingService($item);
+            }
+        }
+        return $itemList;
+    }
+
+}
\ No newline at end of file
diff --git a/src/Response/ShippingServicesSettings/GetSettingsResponse.php b/src/Response/ShippingServicesSettings/GetSettingsResponse.php
new file mode 100644
index 0000000000000000000000000000000000000000..1ab9835a8e986b37af124ee866f623f52ba72196
--- /dev/null
+++ b/src/Response/ShippingServicesSettings/GetSettingsResponse.php
@@ -0,0 +1,32 @@
+<?php
+
+namespace WPDesk\SaasPlatformClient\Response\ShippingServicesSettings;
+
+use WPDesk\SaasPlatformClient\Model\ShippingServiceSetting;
+use WPDesk\SaasPlatformClient\Response\ApiResponse;
+use WPDesk\SaasPlatformClient\Response\Traits\AuthApiResponseDecorator;
+
+class GetSettingsResponse implements ApiResponse
+{
+    use AuthApiResponseDecorator;
+
+    /**
+     * @param array $data
+     * @return array
+     */
+    private function convertHalReferencesToJson(array $data)
+    {
+        foreach ($data['_links'] as $key => $item) {
+            $data[$key] = $item['href'];
+        }
+        return $data;
+    }
+
+    /**
+     * @return ShippingServiceSetting
+     */
+    public function getSetting()
+    {
+        return new ShippingServiceSetting($this->convertHalReferencesToJson($this->getResponseBody()));
+    }
+}
diff --git a/src/Response/ShippingServicesSettings/Test/GetSettingsTestResponse.php b/src/Response/ShippingServicesSettings/Test/GetSettingsTestResponse.php
new file mode 100644
index 0000000000000000000000000000000000000000..ec791b2b3b78bca5b414973dfa56c9d950949174
--- /dev/null
+++ b/src/Response/ShippingServicesSettings/Test/GetSettingsTestResponse.php
@@ -0,0 +1,36 @@
+<?php
+
+namespace WPDesk\SaasPlatformClient\Response\ShippingServicesSettings\Test;
+
+use WPDesk\SaasPlatformClient\Response\ApiResponse;
+use WPDesk\SaasPlatformClient\Response\Exception\EmptyStatusFromResponse;
+use WPDesk\SaasPlatformClient\Response\Traits\AuthApiResponseDecorator;
+
+class GetSettingsTestResponse implements ApiResponse
+{
+    use AuthApiResponseDecorator;
+
+    const MESSAGE = 'message';
+    const STATUS  = 'status';
+
+    public function getMessage()
+    {
+        $responseBody = $this->getResponseBody();
+        if (isset($responseBody[self::MESSAGE])) {
+            return $responseBody[self::MESSAGE];
+        } else {
+            throw EmptyMessageFromResponse::createWithClassInfo(get_class($this->rawResponse), $this->getResponseCode());
+        }
+    }
+
+    public function getStatus()
+    {
+        $responseBody = $this->getResponseBody();
+        if (isset($responseBody[self::STATUS])) {
+            return $responseBody[self::STATUS];
+        } else {
+            throw EmptyStatusFromResponse::createWithClassInfo(get_class($this->rawResponse), $this->getResponseCode());
+        }
+    }
+
+}
diff --git a/src/Response/Status/GetStatusResponse.php b/src/Response/Status/GetStatusResponse.php
new file mode 100644
index 0000000000000000000000000000000000000000..222902c5de693722f8767acfb1b16fdb7512584b
--- /dev/null
+++ b/src/Response/Status/GetStatusResponse.php
@@ -0,0 +1,20 @@
+<?php
+
+namespace WPDesk\SaasPlatformClient\Response\Status;
+
+use WPDesk\SaasPlatformClient\Model\Status;
+use WPDesk\SaasPlatformClient\Response\ApiResponse;
+use WPDesk\SaasPlatformClient\Response\Traits\AuthApiResponseDecorator;
+
+class GetStatusResponse implements ApiResponse
+{
+    use AuthApiResponseDecorator;
+
+    /**
+     * @return Status
+     */
+    public function getStatus()
+    {
+        return new Status($this->getResponseBody());
+    }
+}
diff --git a/src/Response/Traits/ApiResponseDecorator.php b/src/Response/Traits/ApiResponseDecorator.php
new file mode 100644
index 0000000000000000000000000000000000000000..e02c35f6d0a45c0ab406b45111fbf8cd3ce1c0b4
--- /dev/null
+++ b/src/Response/Traits/ApiResponseDecorator.php
@@ -0,0 +1,145 @@
+<?php
+
+namespace WPDesk\SaasPlatformClient\Response\Traits;
+
+use WPDesk\SaasPlatformClient\Response\AuthApiResponse;
+use WPDesk\SaasPlatformClient\Response\RawResponse;
+use WPDesk\SaasPlatformClient\Response\Response;
+
+trait ApiResponseDecorator
+{
+
+    /** @var RawResponse */
+    private $rawResponse;
+
+    /**
+     * RawResponseDecorator constructor.
+     * @param Response $rawResponse
+     */
+    public function __construct(Response $rawResponse)
+    {
+        $this->rawResponse = $rawResponse;
+    }
+
+    /**
+     * Returns response http code
+     *
+     * @return int
+     */
+    public function getResponseCode()
+    {
+        return $this->rawResponse->getResponseCode();
+    }
+
+    /**
+     * Returns response body as array
+     *
+     * @return array
+     */
+    public function getResponseBody()
+    {
+        return $this->rawResponse->getResponseBody();
+    }
+
+    /**
+     * Returns response body as array
+     *
+     * @return array
+     */
+    public function getResponseErrorBody()
+    {
+        return $this->rawResponse->getResponseErrorBody();
+    }
+
+    /**
+     * Returns response body as array
+     *
+     * @return array
+     */
+    public function getResponseHeaders()
+    {
+        return $this->rawResponse->getResponseHeaders();
+    }
+
+    /**
+     * Get links structure to the other request
+     *
+     * @return array
+     */
+    public function getLinks()
+    {
+        $body = $this->getResponseBody();
+        return $body['_links'];
+    }
+
+    /**
+     * Is it a BAD REQUEST response
+     *
+     * @return bool
+     */
+    public function isBadRequest()
+    {
+        return $this->getResponseCode() === RawResponse::RESPONSE_CODE_ERROR_BAD_REQUEST;
+    }
+
+    /**
+     * Is it a DOMAIN NOT ALLOWED response
+     *
+     * @return bool
+     */
+    public function isDomainNotAllowed()
+    {
+        return $this->getResponseCode() === RawResponse::RESPONSE_CODE_DOMAIN_NOT_ALLOWED;
+    }
+
+    /**
+     * Is it a FATAL ERROR response
+     *
+     * @return bool
+     */
+    public function isServerFatalError()
+    {
+        return $this->getResponseCode() === RawResponse::RESPONSE_CODE_ERROR_FATAL;
+    }
+
+    /**
+     * Is any error occured
+     *
+     * @return bool
+     */
+    public function isError()
+    {
+        return $this->rawResponse->isError();
+    }
+
+    /**
+     * Is requested resource exists
+     *
+     * @return bool
+     */
+    public function isNotExists()
+    {
+        return $this->getResponseCode() === AuthApiResponse::RESPONSE_CODE_NOT_EXISTS;
+    }
+
+    /**
+     * Is maintenance.
+     *
+     * @return bool
+     */
+    public function isMaintenance()
+    {
+        return $this->rawResponse->isMaintenance();
+    }
+
+    /**
+     * Get platform version hash string.
+     *
+     * @return bool|string
+     */
+    public function getPlatformVersionHash()
+    {
+        return $this->rawResponse->getPlatformVersionHash();
+    }
+
+    }
\ No newline at end of file
diff --git a/src/Response/Traits/AuthApiResponseDecorator.php b/src/Response/Traits/AuthApiResponseDecorator.php
new file mode 100644
index 0000000000000000000000000000000000000000..5e45ff83a0e82a5da50eb7a0ce9e59c09434e3b8
--- /dev/null
+++ b/src/Response/Traits/AuthApiResponseDecorator.php
@@ -0,0 +1,38 @@
+<?php
+
+namespace WPDesk\SaasPlatformClient\Response\Traits;
+
+use WPDesk\SaasPlatformClient\Response\AuthApiResponse;
+
+trait AuthApiResponseDecorator
+{
+    use ApiResponseDecorator;
+
+    /**
+     * @return bool
+     */
+    public function isBadCredentials()
+    {
+        return $this->getResponseCode() === AuthApiResponse::RESPONSE_CODE_BAD_CREDENTIALS;
+    }
+
+    /**
+     * Is bad credential because token expires
+     *
+     * @return bool
+     */
+    public function isTokenExpired()
+    {
+        return $this->isBadCredentials();
+    }
+
+    /**
+     * Is bad credential because token is invalid
+     *
+     * @return bool
+     */
+    public function isTokenInvalid()
+    {
+        return $this->isBadCredentials();
+    }
+}
\ No newline at end of file
diff --git a/src/Response/Traits/PagedListImplementation.php b/src/Response/Traits/PagedListImplementation.php
new file mode 100644
index 0000000000000000000000000000000000000000..f364978edbec7f04ce436aef19d2eb399e5722e2
--- /dev/null
+++ b/src/Response/Traits/PagedListImplementation.php
@@ -0,0 +1,44 @@
+<?php
+
+namespace WPDesk\SaasPlatformClient\Response\Traits;
+
+trait PagedListImplementation
+{
+    /*
+     * @return array
+     */
+    public function getRawPage()
+    {
+        $body = $this->getResponseBody();
+        if ($body['_embedded'] !== null && $body['_embedded']['item'] !== null) {
+            return $body['_embedded']['item'];
+        }
+        return [];
+    }
+
+    /**
+     * @return int
+     */
+    public function getPageCount()
+    {
+        return (int)floor($this->getItemCount() / $this->getItemsPerPage());
+    }
+
+    /**
+     * @return int
+     */
+    public function getItemsPerPage()
+    {
+        $body = $this->getResponseBody();
+        return (int)$body['itemsPerPage'];
+    }
+
+    /**
+     * @return int
+     */
+    public function getItemCount()
+    {
+        $body = $this->getResponseBody();
+        return (int)$body['totalItems'];
+    }
+}
\ No newline at end of file
diff --git a/src/Response/Users/GetUserResponse.php b/src/Response/Users/GetUserResponse.php
new file mode 100644
index 0000000000000000000000000000000000000000..199a51734513136489edd0e7aceb0b116e977655
--- /dev/null
+++ b/src/Response/Users/GetUserResponse.php
@@ -0,0 +1,20 @@
+<?php
+
+namespace WPDesk\SaasPlatformClient\Response\Users;
+
+use WPDesk\SaasPlatformClient\Model\User;
+use WPDesk\SaasPlatformClient\Response\Response;
+use WPDesk\SaasPlatformClient\Response\Traits\AuthApiResponseDecorator;
+
+final class GetUserResponse implements Response
+{
+    use AuthApiResponseDecorator;
+
+    /**
+     * @return User
+     */
+    public function getUser()
+    {
+        return new User($this->getResponseBody());
+    }
+}
\ No newline at end of file
diff --git a/tests/docker-compose.yaml b/tests/docker-compose.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..2a86b036f682ed318b27b028d2e96dfcd5979afd
--- /dev/null
+++ b/tests/docker-compose.yaml
@@ -0,0 +1,172 @@
+version: '2.0'
+
+services:
+
+  wordpress:
+    image: wpdesknet/phpunit-woocommerce:0-0
+    volumes:
+    - .././:/opt/project
+    depends_on:
+    - mysql0
+    environment:
+      WORDPRESS_DB_NAME: wptest
+      WORDPRESS_DB_USER: mysql
+      WORDPRESS_DB_PASSWORD: mysql
+      WORDPRESS_DB_HOST: mysql0
+
+  wordpress-0-1:
+    image: wpdesknet/phpunit-woocommerce:0-1
+    volumes:
+    - .././:/opt/project
+    depends_on:
+    - mysql1
+    environment:
+      WORDPRESS_DB_NAME: wptest
+      WORDPRESS_DB_USER: mysql
+      WORDPRESS_DB_PASSWORD: mysql
+      WORDPRESS_DB_HOST: mysql1
+
+  wordpress-0-2:
+    image: wpdesknet/phpunit-woocommerce:0-2
+    volumes:
+    - .././:/opt/project
+    depends_on:
+    - mysql2
+    environment:
+      WORDPRESS_DB_NAME: wptest
+      WORDPRESS_DB_USER: mysql
+      WORDPRESS_DB_PASSWORD: mysql
+      WORDPRESS_DB_HOST: mysql2
+
+  wordpress-0-3:
+    image: wpdesknet/phpunit-woocommerce:0-3
+    volumes:
+    - .././:/opt/project
+    depends_on:
+    - mysql3
+    environment:
+      WORDPRESS_DB_NAME: wptest
+      WORDPRESS_DB_USER: mysql
+      WORDPRESS_DB_PASSWORD: mysql
+      WORDPRESS_DB_HOST: mysql3
+
+  wordpress-0-4:
+    image: wpdesknet/phpunit-woocommerce:0-4
+    volumes:
+    - .././:/opt/project
+    depends_on:
+    - mysql4
+    environment:
+      WORDPRESS_DB_NAME: wptest
+      WORDPRESS_DB_USER: mysql
+      WORDPRESS_DB_PASSWORD: mysql
+      WORDPRESS_DB_HOST: mysql4
+
+  wordpress-0-5:
+    image: wpdesknet/phpunit-woocommerce:0-5
+    volumes:
+    - .././:/opt/project
+    depends_on:
+    - mysql5
+    environment:
+      WORDPRESS_DB_NAME: wptest
+      WORDPRESS_DB_USER: mysql
+      WORDPRESS_DB_PASSWORD: mysql
+      WORDPRESS_DB_HOST: mysql5
+
+  wordpress-1-0:
+    image: wpdesknet/phpunit-woocommerce:1-0
+    volumes:
+    - .././:/opt/project
+    depends_on:
+    - mysql0
+    environment:
+      WORDPRESS_DB_NAME: wptest
+      WORDPRESS_DB_USER: mysql
+      WORDPRESS_DB_PASSWORD: mysql
+      WORDPRESS_DB_HOST: mysql0
+
+  wordpress-2-0:
+    image: wpdesknet/phpunit-woocommerce:2-0
+    volumes:
+    - .././:/opt/project
+    depends_on:
+    - mysql0
+    environment:
+      WORDPRESS_DB_NAME: wptest
+      WORDPRESS_DB_USER: mysql
+      WORDPRESS_DB_PASSWORD: mysql
+      WORDPRESS_DB_HOST: mysql0
+
+  wordpress-3-0:
+    image: wpdesknet/phpunit-woocommerce:3-0
+    volumes:
+    - .././:/opt/project
+    depends_on:
+    - mysql0
+    environment:
+      WORDPRESS_DB_NAME: wptest
+      WORDPRESS_DB_USER: mysql
+      WORDPRESS_DB_PASSWORD: mysql
+      WORDPRESS_DB_HOST: mysql0
+
+  wordpress-4-0:
+    image: wpdesknet/phpunit-woocommerce:4-0
+    volumes:
+    - .././:/opt/project
+    depends_on:
+    - mysql0
+    environment:
+      WORDPRESS_DB_NAME: wptest
+      WORDPRESS_DB_USER: mysql
+      WORDPRESS_DB_PASSWORD: mysql
+      WORDPRESS_DB_HOST: mysql0
+
+  mysql0:
+    image: mysql:5.7
+    environment:
+      MYSQL_ROOT_PASSWORD: mysql
+      MYSQL_DATABASE: wptest
+      MYSQL_USER: mysql
+      MYSQL_PASSWORD: mysql
+
+  mysql1:
+    image: mysql:5.7
+    environment:
+      MYSQL_ROOT_PASSWORD: mysql
+      MYSQL_DATABASE: wptest
+      MYSQL_USER: mysql
+      MYSQL_PASSWORD: mysql
+
+  mysql2:
+    image: mysql:5.7
+    environment:
+      MYSQL_ROOT_PASSWORD: mysql
+      MYSQL_DATABASE: wptest
+      MYSQL_USER: mysql
+      MYSQL_PASSWORD: mysql
+
+  mysql3:
+    image: mysql:5.7
+    environment:
+      MYSQL_ROOT_PASSWORD: mysql
+      MYSQL_DATABASE: wptest
+      MYSQL_USER: mysql
+      MYSQL_PASSWORD: mysql
+
+  mysql4:
+    image: mysql:5.7
+    environment:
+      MYSQL_ROOT_PASSWORD: mysql
+      MYSQL_DATABASE: wptest
+      MYSQL_USER: mysql
+      MYSQL_PASSWORD: mysql
+
+  mysql5:
+    image: mysql:5.7
+    environment:
+      MYSQL_ROOT_PASSWORD: mysql
+      MYSQL_DATABASE: wptest
+      MYSQL_USER: mysql
+      MYSQL_PASSWORD: mysql
+
diff --git a/tests/integration/bootstrap.php b/tests/integration/bootstrap.php
new file mode 100644
index 0000000000000000000000000000000000000000..a422fd9c7fea652a15b2aced0b2e6134a5590201
--- /dev/null
+++ b/tests/integration/bootstrap.php
@@ -0,0 +1,28 @@
+<?php
+
+ini_set('error_reporting', E_ALL); // or error_reporting(E_ALL);
+ini_set('display_errors', '1');
+ini_set('display_startup_errors', '1');
+
+require_once __DIR__ . '/../../vendor/autoload.php';
+
+// disable xdebug backtrace
+if ( function_exists( 'xdebug_disable' ) ) {
+	xdebug_disable();
+}
+
+if ( getenv( 'PLUGIN_PATH' ) !== false ) {
+	define( 'PLUGIN_PATH', getenv( 'PLUGIN_PATH' ) );
+} else {
+	define( 'PLUGIN_PATH', __DIR__ . DIRECTORY_SEPARATOR . DIRECTORY_SEPARATOR );
+}
+
+require_once( getenv( 'WP_DEVELOP_DIR' ) . '/tests/phpunit/includes/functions.php' );
+
+tests_add_filter( 'muplugins_loaded', function () {
+}, 100 );
+
+putenv('WP_TESTS_DIR=' . getenv( 'WP_DEVELOP_DIR' ) . '/tests/phpunit');
+require_once( getenv( 'WC_DEVELOP_DIR' ) . '/tests/bootstrap.php' );
+
+do_action('plugins_loaded');
\ No newline at end of file
diff --git a/tests/unit/bootstrap.php b/tests/unit/bootstrap.php
new file mode 100644
index 0000000000000000000000000000000000000000..76b8109582ae17560b77a6e0499b232e09047810
--- /dev/null
+++ b/tests/unit/bootstrap.php
@@ -0,0 +1,9 @@
+<?php
+/**
+ * PHPUnit bootstrap file
+ */
+
+require_once __DIR__ . '/../../vendor/autoload.php';
+
+WP_Mock::setUsePatchwork( true );
+WP_Mock::bootstrap();