Solari

C++ SDK

Two C++17 libraries cover the Solari products: solari::browser (target solari_browser) for browsers, and solari (target solari) for sandboxes. Both are blocking and synchronous. Every call is one round-trip over libcurl, with nlohmann/json for wire types. VMs (GUI desktops) are created with createDesktop(), but driving their GUI needs another SDK; see VMs.

Not published: consumed as source
Neither library ships to a registry. There is no Conan, vcpkg, or system package. You pull them into your build with CMake FetchContent, as below. This applies to every page in this section.

Installation

LibraryTargetNamespaceProduct
pinetree-browser / sdk/cppsolari_browsersolari::browserBrowsers
pinetree-desktop / sdk/cppsolarisolariSandboxes
cmake_minimum_required(VERSION 3.16)
project(my_app CXX)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

include(FetchContent)

# Don't build either SDK's own test target inside your project.
set(SOLARI_BUILD_TESTS OFF CACHE BOOL "" FORCE)

# Browsers: solari::browser
FetchContent_Declare(
  solari_browser
  GIT_REPOSITORY https://github.com/solari-sdk/solari-browser-cpp.git
  GIT_TAG        v0.2.1
)

# Sandboxes: solari
FetchContent_Declare(
  solari
  GIT_REPOSITORY https://github.com/solari-sdk/solari-sandbox-cpp.git
  GIT_TAG        v0.1.4
)

FetchContent_MakeAvailable(solari_browser solari)

add_executable(my_app main.cpp)
target_link_libraries(my_app PRIVATE solari_browser solari)

Take only the FetchContent_Declare you need. The two are independent. Fetched for you at configure time: nlohmann/json v3.11.3, IXWebSocket v11.4.5, and doctest v2.4.11 (tests only). Required from the system: libcurl, a threads library, and OpenSSL for IXWebSocket TLS.

The two libraries share their options and deps
Both declare SOLARI_WITH_WS and SOLARI_BUILD_TESTS, so setting either affects both. They also pin the same versions of nlohmann/json and IXWebSocket, so FetchContent de-duplicates them cleanly when you take both.

Getting Started

Create a browser session

#include <iostream>
#include <solari/browser/browser.hpp>

int main() {
  solari::browser::ClientOptions opts;
  opts.apiKey = "slr_live_...";
  solari::browser::Client client(opts);

  solari::browser::CreateSessionOptions o;
  o.stealth = true;
  o.proxy = std::string("us");

  auto session = client.sessions.create(o);
  std::cout << session.cdpEndpoint << "\n";  // drive this with a CDP client
  client.sessions.release(session.id);
}

There is no launch(). C++ has no Playwright client. See Browsers.

Create a VM

#include <solari/solari.hpp>

solari::ClientOptions opts;
opts.apiKey = "slr_live_...";
opts.baseUrl = "https://api.getsolari.com";
solari::Client client(opts);

solari::CreateSandboxOptions o;
o.template_ = "workstation";

// createDesktop() sends kind:"desktop"; create() stays a headless sandbox.
auto vm = client.createDesktop(o);
vm->connect();

std::cout << *vm->streamUrl() << "\n";  // wss://.../stream/<id>

// commands / files / code / git work on a VM. Mouse, keyboard, and
// screenshots do NOT exist in C++. See the VMs page.
vm->kill();

Requires the desktop entitlement, or the gateway answers 402 PlanError. There is no Desktop class: driving the GUI needs the REST API or the TypeScript SDK. Full detail on VMs.

Create a sandbox

#include <iostream>
#include <solari/solari.hpp>

int main() {
  solari::ClientOptions opts;
  opts.apiKey = "slr_live_...";
  opts.baseUrl = "https://api.getsolari.com";
  solari::Client client(opts);

  auto sbx = client.create();
  sbx->connect();

  solari::CommandOptions o;
  o.args = {"hi"};
  auto r = sbx->commands.run("echo", o);
  std::cout << r.stdout_;  // "hi"

  sbx->kill();
}

Configuration

Each library has its own ClientOptions struct, passed to its Client constructor. Neither reads an environment variable. Pass apiKey explicitly.

FieldTypeDefaultStructNotes
apiKeystd::stringrequiredbothSent as Authorization: Bearer. Throws if empty.
baseUrlstd::stringsee notesbothsolari::browser: https://api.getsolari.com. solari: required, e.g. https://api.getsolari.com.
maxAttemptsint2solari::browserTotal attempts. 2 means one retry.
backoffMslong500solari::browserFixed pause between attempts, not exponential.
timeoutMslong90000solari::browserPer attempt, not per call.
callTimeoutMslong300000solariPer-RPC timeout given to the Sandbox handles this client creates.
429 is never retried
Both transports retry transport errors and 5xx (the browser one 502/503/504/507, with a fixed pause; the sandbox one 5xx and retryable bodies on idempotent requests, with exponential backoff + jitter). Neither retries 429. A concurrency-cap rejection needs caller-side backoff.
Why the browser transport retries 507
The browser gateway itself never emits a 507 — this is the desktop gateway’s transient InsufficientCapacity response. It’s included so the client is correct on its own terms rather than depending on which gateway build it happens to reach.

Reference

ClassTargetPurpose
solari::browser::Clientsolari_browserBrowser control plane: sessions, profiles, proxy countries.
solari::browser::CdpConnectionsolari_browserMinimal raw-CDP escape hatch, behind SOLARI_WITH_WS. Not an automation API.
solari::ClientsolariSandbox entry point: create, connect, get, kill.
solari::SandboxsolariA live session: commands, files, code, git.
VMssolaricreateDesktop(), streamUrl(), and the core namespaces. No GUI surface.