diff --git a/.gitignore b/.gitignore
index fccfd589a1729b5b0556a0ceb3c65141fde675d2..02bce2e92c459988286bf0fede31144a407d64a2 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,7 +2,7 @@
 *.iml
 bin/
 Gopkg.lock
-vendor/
+/vendor
 temp/
 yarn-error.log
 /.project
diff --git a/cpp/.clang-tidy b/cpp/.clang-tidy
index 756a03e01eb88879438b18d2cfd27e75c3092d8b..09a43d11558b23029276572fdd249961288076e0 100644
--- a/cpp/.clang-tidy
+++ b/cpp/.clang-tidy
@@ -1,5 +1,5 @@
 ---
-Checks:          'clang-diagnostic-*,clang-analyzer-*,modernize-*,readability-*,-readability-container-size-empty,-readability-magic-numbers'
+Checks:          'clang-diagnostic-*,clang-analyzer-*,modernize-*,-modernize-use-nodiscard,readability-*,-readability-container-size-empty,-readability-magic-numbers'
 WarningsAsErrors: ''
 HeaderFilterRegex: ''
 AnalyzeTemporaryDtors: false
diff --git a/cpp/CMakeLists.txt b/cpp/CMakeLists.txt
index 81ddf56dc84ab8900038e8c42d02b11bc720bcf4..abf9b756454dc84725418d3d5426339b5354583f 100644
--- a/cpp/CMakeLists.txt
+++ b/cpp/CMakeLists.txt
@@ -1,16 +1,13 @@
 cmake_minimum_required (VERSION 3.16.5)
 
-if(WIN32)
-  set(CMAKE_IGNORE_PATH "C:/Strawberry/c/bin")
-endif()
-
 project (vereign)
 
 # Options
+# FIXME: Add options docs in the README.md
 option(VEREIGN_USE_LLD "Use the lld linker" OFF)
 option(VEREIGN_USE_PRECOMPILED_HEADERS "Use precompiled headers" OFF)
 option(VEREIGN_USE_TIME_TRACE "Use compilation profiler" OFF)
-option(VEREIGN_ENABLE_BENCHMARKING "Enable tests benchmarks" ON)
+option(VEREIGN_ENABLE_BENCHMARKING "Enable tests benchmarks" OFF)
 
 if (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
   if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS "19.0.24215.1")
@@ -29,18 +26,25 @@ else()
 endif()
 
 if (CMAKE_CXX_COMPILER_ID MATCHES "MSVC")
-  add_definitions(-D_WIN32_WINNT=0x0601)
-  set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Release>:Release>")
-  set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
+  # add_definitions(-D_WIN32_WINNT=0x0601)
+  add_definitions(-D_WIN32_WINNT=0x0A00)
+
+  # set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreadedDLL$<$<CONFIG:Release>:Release>")
+  # set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreadedDLL$<$<CONFIG:Debug>:Debug>")
+
+  set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreadedDLL")
+  if (CMAKE_BUILD_TYPE STREQUAL "Debug")
+    set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreadedDebugDLL")
+  endif()
 
   set(CMAKE_C_FLAGS "/DNDEBUG /DWIN32 /D_WINDOWS /W3")
   set(CMAKE_CXX_FLAGS "/DNDEBUG /DWIN32 /D_WINDOWS /W3 /GR /EHsc")
 
-  set(CMAKE_C_FLAGS_DEBUG "/MTd /Zi /Ob0 /Od /RTC1")
-  set(CMAKE_CXX_FLAGS_DEBUG "/MTd /Zi /Ob0 /Od /RTC1")
+  set(CMAKE_C_FLAGS_DEBUG "/MDd /Zi /Ob0 /Od /RTC1")
+  set(CMAKE_CXX_FLAGS_DEBUG "/MDd /Zi /Ob0 /Od /RTC1")
 
-  set(CMAKE_CXX_FLAGS_RELEASE "/Gd /MT /O2 /Oi /Ot /Gy /Zi /GL")
-  set(CMAKE_C_FLAGS_RELEASE "/Gd /MT /O2 /Oi /Ot /Gy /Zi /GL")
+  set(CMAKE_CXX_FLAGS_RELEASE "/Gd /MD /O2 /Oi /Ot /Gy /Zi /GL")
+  set(CMAKE_C_FLAGS_RELEASE "/Gd /MD /O2 /Oi /Ot /Gy /Zi /GL")
 
   if (CMAKE_BUILD_TYPE STREQUAL "Release")
     set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /DEBUG /OPT:REF /OPT:ICF /LTCG")
@@ -64,7 +68,7 @@ endif()
 
 set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
 
-set(CMAKE_CXX_STANDARD 14)
+set(CMAKE_CXX_STANDARD 17)
 set(CMAKE_CXX_EXTENSIONS OFF)
 
 message("Generator: " "${CMAKE_GENERATOR}")
@@ -83,7 +87,6 @@ message("CXX static linker flags: " "${CMAKE_STATIC_LINKER_FLAGS}")
 string(TOLOWER "${CMAKE_BUILD_TYPE}" _build_type)
 set(VENDOR_INSTALL_DIR ${CMAKE_SOURCE_DIR}/cmake-install-vendor-${_build_type} CACHE STRING "vendor directory")
 message(STATUS "Using vendor install dir: ${VENDOR_INSTALL_DIR}")
-#set(VENDOR_INSTALL_DIR /home/daniel/workspace/local)
 set(_cmake_prefix_paths
   ${VENDOR_INSTALL_DIR}
   ${VENDOR_INSTALL_DIR}/grpc
@@ -98,6 +101,9 @@ include(ProtoGenerate)
 enable_testing()
 
 find_package(fmt 6.2.0 REQUIRED)
+if (fmt_FOUND)
+  get_target_property(fmt_INCLUDE_DIR fmt::fmt INTERFACE_INCLUDE_DIRECTORIES)
+endif()
 
 set(OPENSSL_USE_STATIC_LIBS ON)
 set(OPENSSL_ROOT_DIR ${VENDOR_INSTALL_DIR}/boringssl)
@@ -109,7 +115,7 @@ find_package(
   1.72.0
   EXACT
   REQUIRED
-  COMPONENTS regex thread system
+  COMPONENTS regex thread system date_time
 )
 
 find_package(Protobuf CONFIG REQUIRED)
@@ -161,6 +167,7 @@ message(STATUS "summary of build options:
     EXE_LINKER_FLAGS: ${CMAKE_EXE_LINKER_FLAGS_${_build_type}} ${CMAKE_EXE_LINKER_FLAGS}
     WARNCFLAGS:       ${WARNCFLAGS}
     CXX1XCXXFLAGS:    ${CXX1XCXXFLAGS}
+    CMAKE_MSVC_RUNTIME_LIBRARY: ${CMAKE_MSVC_RUNTIME_LIBRARY}
   Libs:
     fmt:            ${fmt_FOUND} [${fmt_VERSION}] (DIR='${fmt_DIR}')
     OpenSSL:        ${OpenSSL_FOUND} [${OPENSSL_VERSION}] (LIBS='${OPENSSL_LIBRARIES}')
diff --git a/cpp/README.md b/cpp/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..46786580c683df123679a7234823655ad1a8ab7f
--- /dev/null
+++ b/cpp/README.md
@@ -0,0 +1,91 @@
+# Vereign C++ Client Library
+
+## Overview
+
+Vereign C++ Client Library allows for digitally signing emails and documents, data encryption,
+and key-based authentication.
+
+FIXME: Add more info about the software architecture.
+
+## Build
+
+The project uses git submodules for the gRPC protobuf definitions.
+
+So after cloning run `git submodule update --init`.
+
+The protobuf definitions and the generated C++ gRPC client/server are located in
+[https://code.vereign.com/code/vcl-proto](https://code.vereign.com/code/vcl-proto) project and 
+are added as submodule at `proto` subdir.
+
+### Windows
+
+You need Visual Studio 2019 or alternatively install just the build tools and c++ compiler - go to
+[https://visualstudio.microsoft.com/downloads/](https://visualstudio.microsoft.com/downloads/)
+then scroll and open `Tools for Visual Studio 2019` and download/install `Visual Studio Build Tools 2019`.
+The 2019 build tools include cmake, and currently it is 3.16.19112601-MSVC_2.
+They also include Ninja build tool.
+
+**NOTE: Currently only builds with Ninja are tested under Windows**
+
+#### Build the third party dependencies
+
+Go to the `vcl/cpp` directory.
+
+First configure the cmake build.
+Open `x64 Native Tools Command Prompt` it is preconfigured with all the needed tools including cmake
+and ninja.
+
+```shell
+> mkdir cmake-build-vendor-debug
+> cd cmake-build-vendor-debug
+> cmake -G Ninja -DCMAKE_BUILD_TYPE=Debug ../vendor
+```
+
+Next build the dependencies.
+Note that this will take a while, and that it could be slowed a lot by the windows defender.
+You can configure the windows defender to the project directory.
+
+```shell
+> ninja
+```
+
+#### Build the vereign library
+
+Go to the `vcl/cpp` directory.
+
+```
+> mkdir cmake-build-debug
+> cd cmake-build-debug
+> cmake -G Ninja -DCMAKE_BUILD_TYPE=Debug ..
+> ninja vereign -v
+```
+
+The `vereign.dll` will be created inside `cmake-build-debug\bin\Debug` directory.
+
+### C API Usage
+
+For C/C++ users, the library has a single header file located in `include\vereign` directory.
+
+The service is started with `vereign_service_start`. This will start a gRPC server in its own thread(s).
+The call returns immediately.
+
+After the service is started you can use your favorite language generated gRPC client to communicate
+with the service.
+
+Use the `vereign_service_selected_port` function to get the listen port of the gRPC server.
+
+When you are finished with the service, for example upon shutdown of the application, one must use
+the `vereign_service_shutdown` API. It will shutdown the service and free any acquired resources.
+Afterwards the returned `vereign_service` pointer from the start call is invalid and must not be used anymore.
+
+For more detailed info check the source code documentation in the header
+[include/vereign/vereign.h](cpp/include/vereign/vereign.h).
+You can also look at C++ usage example in the C API integration test
+[tests/integration/integration_test.cc](cpp/tests/integration/integration_test.cc).
+
+The gRPC APIs are located here [https://code.vereign.com/code/vcl-proto/-/tree/master/proto%2Fvereign%2Fclient_library](https://code.vereign.com/code/vcl-proto/-/tree/master/proto%2Fvereign%2Fclient_library).
+
+FIXME: Add sample integration - for example for C#.
+
+
+TODO: Add more documentation/reference; instructions to generate doxygen reference.
diff --git a/cpp/docs/doxygen.config b/cpp/docs/doxygen.config
index 89459d394d80b5b0cca47920370d319c67baa7ec..2be52903637d12d6ec4ae7903baa7660b45382de 100644
--- a/cpp/docs/doxygen.config
+++ b/cpp/docs/doxygen.config
@@ -792,6 +792,7 @@ WARN_LOGFILE           =
 # Note: If this tag is empty the current directory is searched.
 
 INPUT                  = src
+INPUT                 += include
 
 # This tag can be used to specify the character encoding of the source files
 # that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
@@ -816,8 +817,8 @@ INPUT_ENCODING         = UTF-8
 # *.m, *.markdown, *.md, *.mm, *.dox, *.py, *.pyw, *.f90, *.f95, *.f03, *.f08,
 # *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf and *.qsf.
 
+                         # *.cc \
 FILE_PATTERNS          = *.c \
-                         *.cc \
                          *.cxx \
                          *.cpp \
                          *.c++ \
diff --git a/cpp/include/vereign/vereign.h b/cpp/include/vereign/vereign.h
new file mode 100644
index 0000000000000000000000000000000000000000..c450bd819efba614e91f8c0cac23dfbe4c5503a3
--- /dev/null
+++ b/cpp/include/vereign/vereign.h
@@ -0,0 +1,125 @@
+#ifndef VEREIGN_VEREIGN_H_
+#define VEREIGN_VEREIGN_H_
+
+#ifdef _WIN32
+  #ifdef WIN_EXPORT
+    #define PUBLIC_API __declspec(dllexport)
+  #else
+    #define PUBLIC_API __declspec(dllimport)
+  #endif
+#else
+  #define PUBLIC_API
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Error codes.
+ */
+enum vereign_error_code {
+  VEREIGN_ERR_INTERNAL = 1,
+  VEREIGN_ERR_GRPC_BIND_FAILED = 2
+};
+
+/**
+ * Error object used for the error handling of the APIs.
+ *
+ * The error has a code and error message, which can be obtained by using the corresponding
+ * methods ...
+ */
+typedef struct vereign_error vereign_error;
+
+/**
+ * Destroys ::vereign_error object.
+ *
+ * Error objects are created by the API calls as result of failures.
+ *
+ * It is safe to call it with null err.
+ *
+ * @param err The error to destroy.
+ */
+PUBLIC_API void vereign_error_free(vereign_error* err);
+
+/**
+ * Returns error object's code.
+ *
+ * @param err The error object.
+ * @returns the error code.
+ */
+PUBLIC_API int vereign_error_code(vereign_error* err);
+
+/**
+ * Returns error object's message.
+ *
+ * @param err The error object.
+ * @returns the error message.
+ */
+PUBLIC_API const char* vereign_error_message(vereign_error* err);
+
+/**
+ * Provides the gRPC API services.
+ *
+ * The object is created with ::vereign_service_start method, and shutdown with
+ * ::vereign_service_shutdown.
+ *
+ * All object's methods are named with prefix `vereign_service_`.
+ */
+typedef struct vereign_service vereign_service;
+
+// FIXME: generate SSL keys for gRPC communication.
+/**
+ * Creates ::vereign_service object and starts the gRPC API.
+ *
+ * The returned ::vereign_service object must be destroyed with ::vereign_service_shutdown method.
+ * After successful start, the gRPC bind port can be retrieved with the
+ * ::vereign_service_selected_port method. This is useful if the `listen_address` is in the form
+ * "<host>:" (for example "localhost:"), in which case the port is not provided by the user but
+ * from the OS.
+ *
+ * When the gRPC server cannot bind, `err` will have code VEREIGN_ERR_GRPC_BIND_FAILED.
+ * Any other failures will set `err` with code VEREIGN_ERR_INTERNAL.
+ *
+ * **NOTE: On failure the `err` object must be freed with vereign_error_free method.**
+ *
+ * @param listen_address gRPC listen address, for example "localhost:".
+ * @param vereignHost Vereign restapi host.
+ * @param vereignPort Vereign restapi port - https, 443...
+ * @param err On failure err is initialized with the reason of the failure,
+ *    otherwise err is set to nullptr.
+ * @returns vereign_service object if the gRPC is up and running, otherwise returns nullptr.
+ */
+PUBLIC_API vereign_service* vereign_service_start(
+  const char* listen_address,
+  const char* vereign_host,
+  const char* vereign_port,
+  // FIXME: public_key must come from a storage internally.
+  const char* public_key,
+  vereign_error** err
+);
+
+/**
+ * Retruns the port number selected by the gRPC server of the service.
+ *
+ * Must be called after the service is created with ::vereign_service_start, and before
+ * it is destroyed with ::vereign_service_shutdown.
+ *
+ * @returns the port number selected by the gRPC server of the service.
+ */
+PUBLIC_API int vereign_service_selected_port(vereign_service* service);
+
+/**
+ * Stops and destroys the vereign service.
+ *
+ * It is safe to call with null `service`.
+ *
+ * @param service The object returned by the ::vereign_service_start function.
+ */
+PUBLIC_API void vereign_service_shutdown(vereign_service* service);
+
+#ifdef __cplusplus
+};
+#endif
+
+#endif // VEREIGN_VEREIGN_H_
diff --git a/cpp/src/CMakeLists.txt b/cpp/src/CMakeLists.txt
index c986d16357924b039fc541d518c51c45906c7578..555515506f7c1d62b01e54cf2eeaeeb5401e783b 100644
--- a/cpp/src/CMakeLists.txt
+++ b/cpp/src/CMakeLists.txt
@@ -2,11 +2,15 @@ if (fmt_FOUND)
   get_target_property(FMT_INCLUDE_DIR fmt::fmt INTERFACE_INCLUDE_DIRECTORIES)
 endif()
 
+if (CMAKE_CXX_COMPILER_ID MATCHES "MSVC")
+  add_definitions(-DNOGDI)
+endif()
+
 include_directories(
   ${CMAKE_CURRENT_BINARY_DIR}
   ${CMAKE_SOURCE_DIR}/src
   ${VENDOR_INSTALL_DIR}/include
-  ${VENDOR_INSTALL_DIR}/boost/include
+  ${Boost_INCLUDE_DIRS}
   ${FMT_INCLUDE_DIR}
   ${CMAKE_SOURCE_DIR}/proto/cpp
 )
@@ -26,10 +30,10 @@ list(APPEND PROTO_SRC
   ${CMAKE_SOURCE_DIR}/proto/cpp/code.vereign.com/code/viam-apis/passport-generation-agent/api/api.pb.cc
 )
 add_library(vereignproto STATIC ${PROTO_SRC})
+set_property(TARGET vereignproto PROPERTY POSITION_INDEPENDENT_CODE ON)
 
 target_link_libraries(
   vereignproto
-  fmt::fmt
   protobuf::libprotobuf
   OpenSSL::SSL
   OpenSSL::Crypto
@@ -54,12 +58,31 @@ file(GLOB GENERATED_SERVICES_SRC vereign/service/gen/*.cc)
 list(APPEND VEREIGNLIB_SRC ${GENERATED_SERVICES_SRC})
 
 add_library(vereignlib STATIC ${VEREIGNLIB_SRC})
-target_link_libraries(vereignlib PRIVATE nlohmann_json::nlohmann_json)
+set_property(TARGET vereignlib PROPERTY POSITION_INDEPENDENT_CODE ON)
+target_link_libraries(vereignlib PRIVATE
+  nlohmann_json::nlohmann_json
+)
 target_link_libraries(vereignlib PUBLIC
   vereignproto
+  fmt::fmt
   gRPC::grpc++_reflection
   gRPC::grpc++
+  $<$<CXX_COMPILER_ID:MSVC>:Boost::date_time>
+)
+
+add_library(vereign SHARED
+  vereign/vereign.cc
+)
+target_include_directories(vereign
+  PRIVATE ${CMAKE_SOURCE_DIR}/include
+)
+target_link_libraries(vereign PRIVATE
+  vereignlib
 )
+if (CMAKE_CXX_COMPILER_ID MATCHES "MSVC")
+  # Set the DLLEXPORT variable to export symbols
+  target_compile_definitions(vereign PRIVATE WIN_EXPORT)
+endif()
 
 set(csandbox_sources
   csandbox.cc
@@ -71,7 +94,10 @@ set(csandbox_sources
 add_executable(csandbox ${csandbox_sources})
 
 target_link_libraries(csandbox
-  vereignlib
+  PRIVATE vereignlib
+  $<$<CXX_COMPILER_ID:MSVC>:Boost::date_time>
+  # Boost::thread
+  # vereign
   # fmt::fmt
   # Boost::regex
   # Threads::Threads
diff --git a/cpp/src/csandbox.cc b/cpp/src/csandbox.cc
index 7a1eb95ff82436b8f836f9d8e2bdf1e73651a087..561cf2123f21bd6b5ad1a9b6858d2fb5b2e83a7d 100644
--- a/cpp/src/csandbox.cc
+++ b/cpp/src/csandbox.cc
@@ -1,6 +1,4 @@
-#include <iostream>
 
 auto main(int argc, char* argv[]) -> int {
-  std::cout << "hello" << std::endl;
   return 0;
 }
diff --git a/cpp/src/vereign/grpc/server.cc b/cpp/src/vereign/grpc/server.cc
index c89a27433ec2628e1feccfa54030c47cb80b3d70..fd3c911aae22ff35bb513772a27b7d8d3555b985 100644
--- a/cpp/src/vereign/grpc/server.cc
+++ b/cpp/src/vereign/grpc/server.cc
@@ -32,14 +32,16 @@ public:
     const std::string& vereignPort,
     // FIXME: the public key must come from a storage
     const std::string& publicKey
-  ) : work_guard_{asio::make_work_guard(ioc_)},
+  ) : selected_port_{0},
+    work_guard_{asio::make_work_guard(ioc_)},
     ssl_context_{asio::ssl::context::tlsv12_client},
     client_{std::make_unique<restapi::Client>(
       ioc_, ssl_context_, vereignHost, vereignPort
     )},
     client_session_{std::make_unique<restapi::ClientSession>(
       *client_, publicKey
-    )}
+    )},
+    server_{nullptr}
   {
 
     // FIXME: Verify the remote server's certificate
@@ -60,8 +62,8 @@ public:
     services_registry_.RegisterIntoBuilder(builder);
 
     server_ = builder.BuildAndStart();
-    if (server_ == nullptr) {
-      throw std::runtime_error("server start failed");
+    if (server_ == nullptr || selected_port_ == 0) {
+      throw BindError{};
     }
 
     server_thread_ = std::thread([this]() {
diff --git a/cpp/src/vereign/grpc/server.hh b/cpp/src/vereign/grpc/server.hh
index d2c4cba704280e820ae024d0108c8f892911af40..bcadb25458827207c43b6a0050c92c5dda9cd0fa 100644
--- a/cpp/src/vereign/grpc/server.hh
+++ b/cpp/src/vereign/grpc/server.hh
@@ -7,6 +7,16 @@
 namespace vereign {
 namespace grpc {
 
+/**
+ * BindError is thrown when the Server::Server could not start listening.
+ */
+class BindError: public virtual std::exception {
+public:
+  auto what() const noexcept -> const char* override {
+    return "gRPC listen failed";
+  }
+};
+
 /**
  * Server is a grpc server that provides the Vereign services.
  *
@@ -18,9 +28,13 @@ public:
   /**
    * Constructs and bootstraps the server.
    *
+   * When the gRPC could not start listening a BindError is thrown.
+   * This can happen for number of reasons like invalid hostname or the listen port is already in use.
+   *
    * @param listenAddress gRPC listen address, for example "localhost:".
    * @param vereignHost Vereign restapi host.
    * @param vereignPort Vereign restapi port - https, 443...
+   * @throws BindError when the gRPC server could not start listening.
    */
   explicit Server(
     const std::string& listenAddress,
diff --git a/cpp/src/vereign/restapi/post_result.hh b/cpp/src/vereign/restapi/post_result.hh
index 6d31f5bebb217b9c79d28435f5617a56a3607c81..a975f0efdac8f4fb509d45918bc7a5cf3d31cd56 100644
--- a/cpp/src/vereign/restapi/post_result.hh
+++ b/cpp/src/vereign/restapi/post_result.hh
@@ -12,12 +12,18 @@ struct PostResult {
   RequestPtr Request;
   ResponsePtr Response;
 
+  PostResult()
+    : Request{nullptr},
+      Response{nullptr}
+  {}
+
   PostResult(RequestPtr req, ResponsePtr resp)
     : Request{std::move(req)},
       Response{std::move(resp)}
   {}
 
   PostResult(PostResult&& other) = default;
+  PostResult& operator=(PostResult&& other) = default;
 
   PostResult(const PostResult&) = delete;
   PostResult& operator=(const PostResult&) = delete;
diff --git a/cpp/src/vereign/vereign.cc b/cpp/src/vereign/vereign.cc
new file mode 100644
index 0000000000000000000000000000000000000000..5bbc7e934fe7b9ff917e4b4b75a4a236c8b671f7
--- /dev/null
+++ b/cpp/src/vereign/vereign.cc
@@ -0,0 +1,75 @@
+#include <vereign/vereign.h>
+#include <vereign/grpc/server.hh>
+
+struct vereign_error {
+  int code;
+  std::string msg;
+};
+
+void vereign_error_free(vereign_error* err) {
+  delete err;
+}
+
+auto vereign_error_code(vereign_error* err) -> int {
+  return err->code;
+}
+
+auto vereign_error_message(vereign_error* err) -> const char* {
+  return err->msg.data();
+}
+
+struct vereign_service {
+  std::unique_ptr<vereign::grpc::Server> impl;
+};
+
+// FIXME: generate SSL keys for gRPC communication.
+auto vereign_service_start(
+  const char* listen_address,
+  const char* vereign_host,
+  const char* vereign_port,
+  // FIXME: public_key must come from a storage internally.
+  const char* public_key,
+  vereign_error** err
+) -> vereign_service* {
+  if (err != nullptr) {
+    *err = nullptr;
+  }
+
+  std::unique_ptr<vereign::grpc::Server> serviceImpl;
+
+  try {
+    serviceImpl = std::make_unique<vereign::grpc::Server>(
+      listen_address,
+      vereign_host,
+      vereign_port,
+      public_key
+    );
+
+    return new vereign_service{std::move(serviceImpl)};
+  } catch (const vereign::grpc::BindError& e) {
+    if (err != nullptr) {
+      *err = new vereign_error{VEREIGN_ERR_GRPC_BIND_FAILED, e.what()};
+    }
+  } catch (const std::exception& e) {
+    if (err != nullptr) {
+      *err = new vereign_error{VEREIGN_ERR_INTERNAL, e.what()};
+    }
+  }
+
+  return nullptr;
+}
+
+
+auto vereign_service_selected_port(vereign_service* service) -> int {
+  return service->impl->SelectedPort();
+}
+
+void vereign_service_shutdown(vereign_service* service) {
+  if (service == nullptr) {
+    return;
+  }
+
+  service->impl->Shutdown();
+  delete service;
+}
+
diff --git a/cpp/tests/CMakeLists.txt b/cpp/tests/CMakeLists.txt
index 522c6333935b69525d9e1a2d21b105a610882d5e..62bd6f48b027be1b1605a1f083be7c52d0ecaf00 100644
--- a/cpp/tests/CMakeLists.txt
+++ b/cpp/tests/CMakeLists.txt
@@ -6,3 +6,4 @@ include_directories(
 
 add_subdirectory("protobuf")
 add_subdirectory("vereign")
+add_subdirectory("integration")
diff --git a/cpp/tests/integration/CMakeLists.txt b/cpp/tests/integration/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..9efb1023b1885e94c729c2d0259cd1963e188273
--- /dev/null
+++ b/cpp/tests/integration/CMakeLists.txt
@@ -0,0 +1,26 @@
+include_directories(
+  ${CMAKE_SOURCE_DIR}/src
+  ${CMAKE_SOURCE_DIR}/include
+  # ${VENDOR_INSTALL_DIR}/include
+  ${CMAKE_SOURCE_DIR}/proto/cpp
+)
+
+list(APPEND tests_src
+  ../init_tests.cc
+
+  integration_test.cc
+)
+add_executable(integration_test ${tests_src})
+
+target_link_libraries(integration_test
+  vereign
+  fmt::fmt
+  vereignproto
+  gRPC::grpc++_reflection
+  gRPC::grpc++
+)
+
+add_test(
+  NAME integration_test
+  COMMAND integration_test
+)
diff --git a/cpp/tests/integration/integration_test.cc b/cpp/tests/integration/integration_test.cc
new file mode 100644
index 0000000000000000000000000000000000000000..ef42c7201cd946c0b613616ab45813340c351dd8
--- /dev/null
+++ b/cpp/tests/integration/integration_test.cc
@@ -0,0 +1,152 @@
+#include <vereign/vereign.h>
+#include <util/env.hh>
+#include <vereign/client_library/types.gen.pb.h>
+#include <vereign/client_library/passport_api.gen.grpc.pb.h>
+#include <vereign/core/scope_guard.hh>
+#include <grpcpp/create_channel.h>
+
+#include <catch2/catch.hpp>
+
+TEST_CASE("C API integration", "[.integration]") {
+  auto publicKey = vereign::test::RequireEnv("TEST_VEREIGN_PUB_KEY");
+  auto host = vereign::test::RequireEnv("TEST_VEREIGN_API_HOST");
+  auto port = vereign::test::GetEnv("TEST_VEREIGN_API_PORT", "https");
+
+  // start the service
+  vereign_error* err = nullptr;
+  auto service = vereign_service_start(
+    "localhost:",
+    host.data(),
+    port.data(),
+    publicKey.data(),
+    &err
+  );
+  CHECK(service != nullptr);
+  CHECK(err == nullptr);
+  auto on_exit = vereign::core::MakeScopeGuard([service] {
+    vereign_service_shutdown(service);
+  });
+
+  int listen_port = vereign_service_selected_port(service);
+
+  // start using the gRPC API with a C++ gRPC client.
+  auto channel = ::grpc::CreateChannel(
+    "localhost:" + std::to_string(listen_port),
+    ::grpc::InsecureChannelCredentials()
+  );
+
+  auto client = vereign::client_library::PassportAPI::NewStub(channel);
+
+  vereign::client_library::ListPassportsForm req;
+  vereign::client_library::ListPassportsFormResponse resp;
+  ::grpc::ClientContext ctx;
+  auto status = client->ListPassports(&ctx, req, &resp);
+
+  // std::cout << vereign::test::ProtobufToJson(resp) << std::endl;
+
+  REQUIRE(status.error_message() == "");
+  REQUIRE(resp.error() == "");
+  CHECK(resp.status() == "OK");
+  CHECK(resp.code() == "200");
+  CHECK(resp.data().size() > 0);
+  for (auto& passport : resp.data()) {
+    CHECK(passport.uuid().size() == 36);
+  }
+
+  req.Clear();
+  resp.Clear();
+  ::grpc::ClientContext manually_ctx;
+  status = client->ListPassportsManually(&manually_ctx, req, &resp);
+
+  // std::cout << vereign::test::ProtobufToJson(resp) << std::endl;
+
+  REQUIRE(status.error_message() == "");
+  REQUIRE(resp.error() == "");
+  CHECK(resp.status() == "OK");
+  CHECK(resp.code() == "200");
+  CHECK(resp.data().size() > 0);
+  for (auto& passport : resp.data()) {
+    CHECK(passport.uuid().size() == 36);
+  }
+
+  vereign::client_library::GetInteractionsForm getInterReq;
+  getInterReq.set_uuid(resp.data().at(0).uuid());
+  vereign::client_library::GetInteractionsFormResponse getInterResp;
+  ::grpc::ClientContext getInterCtx;
+  status = client->GetInteractions(&getInterCtx, getInterReq, &getInterResp);
+  CHECK(status.error_message() == "");
+  CHECK(getInterResp.error() == "");
+  CHECK(getInterResp.status() == "OK");
+  CHECK(getInterResp.code() == "200");
+  for (auto& interaction : getInterResp.data()) {
+    CHECK(interaction.subject().size() > 0);
+    CHECK(interaction.passport().size() == 36);
+  }
+
+  // std::cout << vereign::test::ProtobufToJson(getDIDsResp) << std::endl;
+
+  grpc_shutdown();
+  google::protobuf::ShutdownProtobufLibrary();
+}
+
+TEST_CASE("vereign_service_start") {
+  SECTION("success") {
+    vereign_error* err = nullptr;
+    auto service = vereign_service_start(
+      "localhost:",
+      "",
+      "",
+      "",
+      &err
+    );
+
+    CHECK(service != nullptr);
+    CHECK(err == nullptr);
+
+    vereign_service_shutdown(service);
+  }
+
+  SECTION("invalid listen address") {
+    vereign_error* err = nullptr;
+    auto service = vereign_service_start(
+      "##$$",
+      "",
+      "",
+      "",
+      &err
+    );
+
+    CHECK(service == nullptr);
+    CHECK(err != nullptr);
+    CHECK(vereign_error_code(err) == VEREIGN_ERR_GRPC_BIND_FAILED);
+    std::string error_message = vereign_error_message(err);
+    CHECK(error_message == "gRPC listen failed");
+
+    vereign_error_free(err);
+    vereign_service_shutdown(service);
+  }
+}
+
+TEST_CASE("vereign_service_selected_port") {
+  vereign_error* err = nullptr;
+  auto service = vereign_service_start(
+    "localhost:",
+    "",
+    "",
+    "",
+    &err
+  );
+
+  REQUIRE(service != nullptr);
+  REQUIRE(err == nullptr);
+
+  auto port = vereign_service_selected_port(service);
+  CHECK((port > 0 && port <= 65535));
+
+  vereign_service_shutdown(service);
+}
+
+TEST_CASE("vereign_service_shutdown") {
+  // shutdown must not fail with nullptr
+  vereign_service_shutdown(nullptr);
+}
diff --git a/cpp/tests/util/protobuf.cc b/cpp/tests/util/protobuf.cc
index 544c5770d1b70a5a06192488cdcbc85adfd0731b..05e1c791a91878f1d09a4c0068227de89e7937e1 100644
--- a/cpp/tests/util/protobuf.cc
+++ b/cpp/tests/util/protobuf.cc
@@ -1,8 +1,7 @@
-#include "vereign/grpc/json/encoder.hh"
+#include <vereign/grpc/json/encoder.hh>
 #include <util/protobuf.hh>
 
 #include <google/protobuf/util/json_util.h>
-#include <fmt/core.h>
 
 #include <catch2/catch.hpp>
 
diff --git a/cpp/tests/vereign/CMakeLists.txt b/cpp/tests/vereign/CMakeLists.txt
index 4deb797f1635045a7c356cbcfa1f0fcd8eae940c..2c2b6fce316e7721ed05a80e53330200081a4486 100644
--- a/cpp/tests/vereign/CMakeLists.txt
+++ b/cpp/tests/vereign/CMakeLists.txt
@@ -1,12 +1,15 @@
 
+if (CMAKE_CXX_COMPILER_ID MATCHES "MSVC")
+  add_definitions(-DNOGDI)
+endif()
 
 include_directories(
   ${CMAKE_SOURCE_DIR}/src
   ${VENDOR_INSTALL_DIR}/include
   ${CMAKE_SOURCE_DIR}/proto/cpp
+  ${Boost_INCLUDE_DIRS}
 )
 
-
 list(APPEND tests_src
   init_tests.cc
   ../util/protobuf.cc
diff --git a/cpp/vendor/CMakeLists.txt b/cpp/vendor/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..7d4cb218c8cc4ae5f18c2a2d6a792071df35ab0d
--- /dev/null
+++ b/cpp/vendor/CMakeLists.txt
@@ -0,0 +1,70 @@
+cmake_minimum_required (VERSION 3.16.5)
+
+project (vereign-vendor)
+
+if (CMAKE_CXX_COMPILER_ID MATCHES "MSVC")
+  add_definitions(-D_WIN32_WINNT=0x0601)
+
+  set(CMAKE_C_FLAGS "/DNDEBUG /DWIN32 /D_WINDOWS /W3")
+  set(CMAKE_CXX_FLAGS "/DNDEBUG /DWIN32 /D_WINDOWS /W3 /GR /EHsc")
+
+  set(CMAKE_C_FLAGS_DEBUG "/MDd /Zi /Ob0 /Od /RTC1")
+  set(CMAKE_CXX_FLAGS_DEBUG "/MDd /Zi /Ob0 /Od /RTC1")
+
+  set(CMAKE_CXX_FLAGS_RELEASE "/Gd /MD /O2 /Oi /Ot /Gy /Zi /GL")
+  set(CMAKE_C_FLAGS_RELEASE "/Gd /MD /O2 /Oi /Ot /Gy /Zi /GL")
+
+  set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Release>:Release>")
+  set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>DLL")
+
+  set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreadedDLL")
+  if (CMAKE_BUILD_TYPE STREQUAL "Debug")
+    set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreadedDebugDLL")
+  endif()
+endif()
+
+if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
+  set(CMAKE_C_FLAGS_RELEASE "-g -O3 -Wall -Wextra -pedantic")
+  set(CMAKE_C_FLAGS_DEBUG "-g -O0 -Wall -Wextra -pedantic")
+  set(CMAKE_CXX_FLAGS_RELEASE "-g -O3 -Wall -Wextra -pedantic")
+  set(CMAKE_CXX_FLAGS_DEBUG "-g -O0 -Wall -Wextra -pedantic")
+endif()
+
+if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
+  set(CMAKE_C_FLAGS_RELEASE "-g -O3 -Wall -Wextra -pedantic")
+  set(CMAKE_C_FLAGS_DEBUG "-g -O0 -Wall -Wextra -pedantic")
+  set(CMAKE_CXX_FLAGS_RELEASE "-g -O3 -Wall -Wextra -pedantic")
+  set(CMAKE_CXX_FLAGS_DEBUG "-g -O0 -Wall -Wextra -pedantic")
+endif()
+
+set(CMAKE_CXX_STANDARD 14)
+set(CMAKE_CXX_EXTENSIONS OFF)
+
+string(TOLOWER "${CMAKE_BUILD_TYPE}" _build_type)
+set(VENDOR_INSTALL_DIR ${CMAKE_SOURCE_DIR}/../cmake-install-vendor-${_build_type} CACHE STRING "vendor directory")
+set(CMAKE_PREFIX_PATH ${VENDOR_INSTALL_DIR} CACHE STRING "")
+option(CMAKE_FIND_USE_CMAKE_SYSTEM_PATH NO)
+
+include(FetchContent)
+include(ExternalProject)
+
+include(fmt.cmake)
+include(boring_ssl.cmake)
+include(boost.cmake)
+include(grpc.cmake)
+include(nlohmann.cmake)
+
+string(TOUPPER "${CMAKE_BUILD_TYPE}" _build_type)
+message(STATUS "Summary:
+
+  Vendor install dir: ${VENDOR_INSTALL_DIR}
+  Compiler:
+    Build type:     ${CMAKE_BUILD_TYPE}
+    C compiler:     ${CMAKE_C_COMPILER}
+    CFLAGS:         ${CMAKE_C_FLAGS_${_build_type}} ${CMAKE_C_FLAGS}
+    C++ compiler:   ${CMAKE_CXX_COMPILER}
+    CXXFLAGS:       ${CMAKE_CXX_FLAGS_${_build_type}} ${CMAKE_CXX_FLAGS}
+    WARNCFLAGS:     ${WARNCFLAGS}
+    CXX1XCXXFLAGS:  ${CXX1XCXXFLAGS}
+    CMAKE_MSVC_RUNTIME_LIBRARY: ${CMAKE_MSVC_RUNTIME_LIBRARY}
+")
diff --git a/cpp/vendor/boost.cmake b/cpp/vendor/boost.cmake
new file mode 100644
index 0000000000000000000000000000000000000000..430902d781c72e6b107b4709b13a84f7160a1220
--- /dev/null
+++ b/cpp/vendor/boost.cmake
@@ -0,0 +1,38 @@
+include(ExternalProject)
+
+set(_boost_libs regex system thread date_time)
+
+if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
+  list(TRANSFORM _boost_libs PREPEND --with-)
+
+  set(_configure_command <SOURCE_DIR>/bootstrap.bat)
+  set(_build_command <SOURCE_DIR>/b2 install --prefix=<INSTALL_DIR> ${_boost_libs} link=static)
+  set(_install_command "")
+elseif(CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
+  set(_boost_toolset clang)
+  set(_boost_cxx_flags "-std=c++${CMAKE_CXX_STANDARD} -fPIC")
+  set(_boost_c_flags "-fPIC")
+  string(REPLACE ";" "," _boost_libs "${_boost_libs}")
+
+  set(_configure_command <SOURCE_DIR>/bootstrap.sh --prefix=<INSTALL_DIR> --with-toolset=${_boost_toolset} --with-libraries=${_boost_libs})
+  set(_build_command <SOURCE_DIR>/b2 toolset=${_boost_toolset} cxxflags=${_boost_cxx_flags} cflags=${_boost_c_flags})
+  set(_install_command <SOURCE_DIR>/b2 install)
+endif()
+
+ExternalProject_Add(boostlib
+  PREFIX boost
+  URL https://dl.bintray.com/boostorg/release/1.72.0/source/boost_1_72_0.zip
+  URL_HASH SHA256=8c20440aaba21dd963c0f7149517445f50c62ce4eb689df2b5544cc89e6e621e
+  BUILD_IN_SOURCE ON
+  INSTALL_DIR ${VENDOR_INSTALL_DIR}/boost
+
+  USES_TERMINAL_DOWNLOAD ON
+  USES_TERMINAL_UPDATE ON
+  USES_TERMINAL_CONFIGURE ON
+  USES_TERMINAL_BUILD ON
+  USES_TERMINAL_INSTALL ON
+
+  CONFIGURE_COMMAND "${_configure_command}"
+  BUILD_COMMAND "${_build_command}"
+  INSTALL_COMMAND "${_install_command}"
+)
diff --git a/cpp/vendor/boring_ssl.cmake b/cpp/vendor/boring_ssl.cmake
new file mode 100644
index 0000000000000000000000000000000000000000..91cfaa725dd36053bec5ea75a9f22dfb496e5ed6
--- /dev/null
+++ b/cpp/vendor/boring_ssl.cmake
@@ -0,0 +1,44 @@
+
+if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
+  set(_install_command
+    ${CMAKE_COMMAND} -E copy crypto.lib <INSTALL_DIR>/lib/crypto.lib
+    COMMAND ${CMAKE_COMMAND} -E copy ssl.lib <INSTALL_DIR>/lib/ssl.lib
+    COMMAND ${CMAKE_COMMAND} -E copy_directory <SOURCE_DIR>/src/include <INSTALL_DIR>/include
+  )
+elseif(CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
+  set(_install_command
+    ${CMAKE_COMMAND} -E copy libcrypto.a <INSTALL_DIR>/lib/libcrypto.a
+    COMMAND ${CMAKE_COMMAND} -E copy libssl.a <INSTALL_DIR>/lib/libssl.a
+    COMMAND ${CMAKE_COMMAND} -E copy_directory <SOURCE_DIR>/src/include <INSTALL_DIR>/include
+  )
+endif()
+
+ExternalProject_Add(boringssllib
+  PREFIX boringssl
+  GIT_REPOSITORY git@github.com:google/boringssl.git
+  GIT_TAG 1c2769383f027befac5b75b6cedd25daf3bf4dcf
+  INSTALL_DIR ${VENDOR_INSTALL_DIR}/boringssl
+
+  USES_TERMINAL_DOWNLOAD ON
+  USES_TERMINAL_UPDATE ON
+  USES_TERMINAL_CONFIGURE ON
+  USES_TERMINAL_BUILD ON
+  USES_TERMINAL_INSTALL ON
+
+  CMAKE_CACHE_ARGS
+  -DCMAKE_C_COMPILER:STRING=${CMAKE_C_COMPILER}
+  -DCMAKE_CXX_COMPILER:STRING=${CMAKE_CXX_COMPILER}
+  -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR>
+  -DCMAKE_BUILD_TYPE:STRING=${CMAKE_BUILD_TYPE}
+  -DCMAKE_MSVC_RUNTIME_LIBRARY:STRING=${CMAKE_MSVC_RUNTIME_LIBRARY}
+  -DCMAKE_C_FLAGS:STRING=${CMAKE_C_FLAGS}
+  -DCMAKE_CXX_FLAGS:STRING=${CMAKE_CXX_FLAGS}
+  -DCMAKE_C_FLAGS_DEBUG:STRING=${CMAKE_C_FLAGS_DEBUG}
+  -DCMAKE_CXX_FLAGS_DEBUG:STRING=${CMAKE_CXX_FLAGS_DEBUG}
+  -DCMAKE_C_FLAGS_RELEASE:STRING=${CMAKE_C_FLAGS_RELEASE}
+  -DCMAKE_CXX_FLAGS_RELEASE:STRING=${CMAKE_CXX_FLAGS_RELEASE}
+  -DBUILD_SHARED_LIBS:BOOL=OFF
+  -DCMAKE_POSITION_INDEPENDENT_CODE:BOOL=ON
+
+  INSTALL_COMMAND "${_install_command}"
+)
diff --git a/cpp/vendor/fmt.cmake b/cpp/vendor/fmt.cmake
new file mode 100644
index 0000000000000000000000000000000000000000..55359ac9333f8f58e3ce1a95d03b2165913ecb7e
--- /dev/null
+++ b/cpp/vendor/fmt.cmake
@@ -0,0 +1,28 @@
+
+ExternalProject_Add(fmtlib
+  PREFIX fmt
+  GIT_REPOSITORY git@github.com:fmtlib/fmt.git
+  GIT_TAG 6.2.0
+  INSTALL_DIR ${VENDOR_INSTALL_DIR}/fmt
+
+  USES_TERMINAL_DOWNLOAD ON
+  USES_TERMINAL_UPDATE ON
+  USES_TERMINAL_CONFIGURE ON
+  USES_TERMINAL_BUILD ON
+  USES_TERMINAL_INSTALL ON
+
+  CMAKE_CACHE_ARGS
+  -DCMAKE_BUILD_TYPE:STRING=${CMAKE_BUILD_TYPE}
+  -DCMAKE_MSVC_RUNTIME_LIBRARY:STRING=${CMAKE_MSVC_RUNTIME_LIBRARY}
+  -DCMAKE_C_COMPILER:STRING=${CMAKE_C_COMPILER}
+  -DCMAKE_CXX_COMPILER:STRING=${CMAKE_CXX_COMPILER}
+  -DCMAKE_C_FLAGS:STRING=${CMAKE_C_FLAGS}
+  -DCMAKE_CXX_FLAGS:STRING=${CMAKE_CXX_FLAGS}
+  -DCMAKE_C_FLAGS_DEBUG:STRING=${CMAKE_C_FLAGS_DEBUG}
+  -DCMAKE_CXX_FLAGS_DEBUG:STRING=${CMAKE_CXX_FLAGS_DEBUG}
+  -DCMAKE_C_FLAGS_RELEASE:STRING=${CMAKE_C_FLAGS_RELEASE}
+  -DCMAKE_CXX_FLAGS_RELEASE:STRING=${CMAKE_CXX_FLAGS_RELEASE}
+  -DCMAKE_POSITION_INDEPENDENT_CODE:BOOL=ON
+  -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR>
+  -DFMT_TEST:BOOL=OFF
+)
diff --git a/cpp/vendor/grpc.cmake b/cpp/vendor/grpc.cmake
new file mode 100644
index 0000000000000000000000000000000000000000..a33a809c38cf41bcf9c0136dc51fab3f9bb4176a
--- /dev/null
+++ b/cpp/vendor/grpc.cmake
@@ -0,0 +1,33 @@
+
+ExternalProject_Add(grpclib
+  PREFIX grpc
+  GIT_REPOSITORY git@github.com:grpc/grpc.git
+  GIT_TAG v1.28.1
+  GIT_SHALLOW ON
+  INSTALL_DIR ${VENDOR_INSTALL_DIR}/grpc
+  DEPENDS boringssllib
+
+  USES_TERMINAL_DOWNLOAD ON
+  USES_TERMINAL_UPDATE ON
+  USES_TERMINAL_CONFIGURE ON
+  USES_TERMINAL_BUILD ON
+  USES_TERMINAL_INSTALL ON
+
+  CMAKE_CACHE_ARGS
+  -DCMAKE_C_COMPILER:STRING=${CMAKE_C_COMPILER}
+  -DCMAKE_CXX_COMPILER:STRING=${CMAKE_CXX_COMPILER}
+  -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR>
+  -DCMAKE_BUILD_TYPE:STRING=${CMAKE_BUILD_TYPE}
+  -DCMAKE_MSVC_RUNTIME_LIBRARY:STRING=${CMAKE_MSVC_RUNTIME_LIBRARY}
+  -DCMAKE_C_FLAGS:STRING=${CMAKE_C_FLAGS}
+  -DCMAKE_CXX_FLAGS:STRING=${CMAKE_CXX_FLAGS}
+  -DCMAKE_C_FLAGS_DEBUG:STRING=${CMAKE_C_FLAGS_DEBUG}
+  -DCMAKE_CXX_FLAGS_DEBUG:STRING=${CMAKE_CXX_FLAGS_DEBUG}
+  -DCMAKE_C_FLAGS_RELEASE:STRING=${CMAKE_C_FLAGS_RELEASE}
+  -DCMAKE_CXX_FLAGS_RELEASE:STRING=${CMAKE_CXX_FLAGS_RELEASE}
+  -DBUILD_SHARED_LIBS:BOOL=OFF
+  -DgRPC_SSL_PROVIDER:STRING=package
+  -DOPENSSL_USE_STATIC_LIBS:BOOL=ON
+  -DOPENSSL_ROOT_DIR:STRING=${VENDOR_INSTALL_DIR}/boringssl
+  -DgRPC_INSTALL:BOOL=ON
+)
diff --git a/cpp/vendor/nlohmann.cmake b/cpp/vendor/nlohmann.cmake
new file mode 100644
index 0000000000000000000000000000000000000000..93272436440658733a42926a90b4cc156767bae6
--- /dev/null
+++ b/cpp/vendor/nlohmann.cmake
@@ -0,0 +1,27 @@
+
+ExternalProject_Add(nlohmannlib
+  PREFIX nlohmann
+  GIT_REPOSITORY git@github.com:nlohmann/json.git
+  GIT_TAG v3.7.3
+  INSTALL_DIR ${VENDOR_INSTALL_DIR}/nlohmann
+
+  USES_TERMINAL_DOWNLOAD ON
+  USES_TERMINAL_UPDATE ON
+  USES_TERMINAL_CONFIGURE ON
+  USES_TERMINAL_BUILD ON
+  USES_TERMINAL_INSTALL ON
+
+  CMAKE_CACHE_ARGS
+  -DCMAKE_BUILD_TYPE:STRING=${CMAKE_BUILD_TYPE}
+  -DCMAKE_MSVC_RUNTIME_LIBRARY:STRING=${CMAKE_MSVC_RUNTIME_LIBRARY}
+  -DCMAKE_C_COMPILER:STRING=${CMAKE_C_COMPILER}
+  -DCMAKE_CXX_COMPILER:STRING=${CMAKE_CXX_COMPILER}
+  -DCMAKE_C_FLAGS:STRING=${CMAKE_C_FLAGS}
+  -DCMAKE_CXX_FLAGS:STRING=${CMAKE_CXX_FLAGS}
+  -DCMAKE_C_FLAGS_DEBUG:STRING=${CMAKE_C_FLAGS_DEBUG}
+  -DCMAKE_CXX_FLAGS_DEBUG:STRING=${CMAKE_CXX_FLAGS_DEBUG}
+  -DCMAKE_C_FLAGS_RELEASE:STRING=${CMAKE_C_FLAGS_RELEASE}
+  -DCMAKE_CXX_FLAGS_RELEASE:STRING=${CMAKE_CXX_FLAGS_RELEASE}
+  -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR>
+  -DJSON_BuildTests:BOOL=OFF
+)