Skip to content

C++ SDK: Getting Started

The Aureva C++ SDK is a public, standalone, permissively licensed library. You download it from the SDK GitHub release, drop it into your project, embed your application config, fill in a single constructor call plus init(), build for your target architecture, and call init() then license() then check().

This guide walks that integration end to end, in order.


The SDK release mirrors the layout of a typical C++ example distribution:

FilePurpose
include/aureva/aureva.hppThe only public header — declares aureva::Api, response, and user_data_t
include/aureva/version.hppAUREVA_SDK_VERSION* macros and aureva::sdk_version()
lib/x64/aureva_x64.libPrebuilt static library for x64
lib/x86/aureva_x86.libPrebuilt static library for x86
example/main.cppA minimal working integration
example/aureva_app_config.hA placeholder config header (replace with your generated one)
README.md / LICENSEDocs and the permissive license

Obtain the SDK from its GitHub release (the same surface linked from your dashboard’s per-application integration tab). Each release is a tagged, semantically versioned build with the prebuilt per-architecture libraries and the public header(s) attached as downloadable assets, so you can pin a known-good build without compiling from source.

You can confirm which build you linked at runtime:

#include <aureva/aureva.hpp>
#include <cstdio>
std::printf("Aureva SDK %s\n", aureva::sdk_version()); // e.g. "1.0.0"

Place the header on your include path and link the static library for the architecture you build:

  • Add include/ to your compiler’s include directories so #include <aureva/aureva.hpp> resolves.
  • Link aureva_x64.lib for an x64 build, or aureva_x86.lib for an x86 build.

That is the entire footprint of the SDK in your build — one header to include and one static library to link.


Your application’s secret values are not passed as plain strings in your source. They are generated for you, already encrypted, by the dashboard’s Application management area, which emits a C++ header named aureva_app_config.h. Drop that generated header onto your include path and rebuild.

The header carries five compile-time values:

ValueWhat it is
scriptIdThe application identifier
pkThe project main key, in its server-encrypted, embeddable form
sk1Project secret key 1, server-encrypted
sk2Project secret key 2, server-encrypted
client versionThe version string the SDK reports on every init request

If you build the SDK standalone without a generated header, it falls back to a built-in placeholder config. The placeholder values are clearly marked and non-functional by design: the SDK reports them as unconfigured and fails closed, so a placeholder build can never authenticate against the live backend. Replace the placeholder header with your generated one before shipping.

A placeholder header looks like this (illustrative — not real keys):

// aureva_app_config.h — PLACEHOLDER VALUES ONLY. Replace with the header
// generated for your application by the Aureva dashboard. Never commit real keys.
namespace aureva_cfg_embed {
inline auto ScriptId() { return OBF("AUREVA_SCRIPT_ID_PLACEHOLDER"); }
inline auto ProjectMainKey() { return OBF("AUREVA_PK_ENCRYPTED_BLOB_PLACEHOLDER"); }
inline auto ProjectSecretKey1() { return OBF("AUREVA_SK1_ENCRYPTED_BLOB_PLACEHOLDER"); }
inline auto ProjectSecretKey2() { return OBF("AUREVA_SK2_ENCRYPTED_BLOB_PLACEHOLDER"); }
inline auto ClientVersion() { return OBF("1.0"); }
}

The public surface is a small, familiar application object, aureva::Api. The minimal setup is a single constructor call taking the four application-secret values, plus an explicit init(). The base URL is optional and defaults to https://api.aureva.cc.

#include <aureva/aureva.hpp>
// Construct from your application secret. The values come from the encrypted,
// obfuscated forms in your generated aureva_app_config.h — never raw keys.
aureva::Api app(
OBF("AUREVA_SCRIPT_ID"), // scriptId (compile-time obfuscated, placeholder)
OBF("AUREVA_PK_ENCRYPTED_BLOB"), // pk (server-encrypted, placeholder)
OBF("AUREVA_SK1_ENCRYPTED_BLOB"), // sk1 (placeholder)
OBF("AUREVA_SK2_ENCRYPTED_BLOB") // sk2 (URL omitted => defaults to api.aureva.cc)
);

Step 5 — Build for your target architecture

Section titled “Step 5 — Build for your target architecture”

The SDK builds with CMake using the standard generator-platform mechanism. Run the configure step then the build step for each architecture. The static library lands in the documented output location below.

x64 (Release) — produces build/x64/Release/aureva_x64.lib:

Terminal window
cmake -S . -B build/x64 -G "Visual Studio 17 2022" -A x64
cmake --build build/x64 --config Release

x86 (Release) — produces build/x86/Release/aureva_x86.lib:

Terminal window
cmake -S . -B build/x86 -G "Visual Studio 17 2022" -A Win32
cmake --build build/x86 --config Release

The Visual Studio generator is multi-config, so the configuration is selected at build time. Swap --config Release for --config Debug to produce the debug build; the Release configuration is the one published as the SDK release.

The CMake build links only the Win32 import libraries the SDK requires (for example winhttp, bcrypt, crypt32) and introduces no host-application dependency. This build is independent of any consuming application’s own build.


Step 6 — Call init(), then license(), then check()

Section titled “Step 6 — Call init(), then license(), then check()”

Authentication runs in three calls, always in this order. Each call updates app.response before it returns — read app.response.success after each one.

#include <aureva/aureva.hpp>
#include <chrono>
#include <thread>
int main() {
aureva::Api app(
OBF("AUREVA_SCRIPT_ID"), // placeholder — use your generated config
OBF("AUREVA_PK_ENCRYPTED_BLOB"),
OBF("AUREVA_SK1_ENCRYPTED_BLOB"),
OBF("AUREVA_SK2_ENCRYPTED_BLOB")
);
// 1) init(): local integrity self-tests only. NO network, NO activation.
app.init();
if (!app.response.success) {
// Fail closed: do not proceed.
return 1;
}
// 2) license(key): activate with the user's key (init -> verify-alive).
app.license(userEnteredKey);
if (!app.response.success) {
// Fail closed: activation denied (bad key, transport failure,
// version too old, etc.). app.response.message says why (non-secret).
return 1;
}
// Authorized. Read entitlement / session info from user_data.
const auto& u = app.user_data;
// u.hwid, u.ip, u.tier, u.premium, u.expiry / u.expires_at
// 3) check(): validate the live session at a fixed interval (<= 60s),
// without re-entering the key. Act on a failed result.
for (;;) {
std::this_thread::sleep_for(std::chrono::seconds(30));
app.check();
if (!app.response.success) {
// Session no longer authorized (kick, integrity failure, etc.).
// Stop permitting gated features before the next check.
break;
}
}
return 0;
}

What each call does:

  • init() runs the SDK’s native integrity self-tests. It performs no network operation and no activation. success is true only if every self-test passes.
  • license(key) trims the key and runs the activation flow (init request → verify-alive) within its timeout. success is true only when both stages authorize. An empty or all-whitespace key fails closed with no network operation.
  • check() validates the live session via the heartbeat / verify-alive flow without re-entering the key. success tracks whether the session is still authorized. Call it at a fixed interval of no more than 60 seconds and act on a failed result.

The success / message fail-closed contract

Section titled “The success / message fail-closed contract”

Every public call updates the response struct before returning:

struct response {
bool success; // outcome of the most recent call
std::string message; // non-empty, non-secret when success == false
};

The contract you rely on:

  • Check success after init() and after license() before doing anything that depends on authorization. This is the fail-closed usage pattern — treat anything other than success == true as denied.
  • When success is false, message is a non-empty, non-secret diagnostic explaining the cause. It never contains key or secret material.
  • Calls made out of order fail closed: license() before a successful init(), check() before a successful license(), or license() with a blank key all set success = false, perform no network operation, and never report the session as authorized.
  • Any transport failure, timeout, or backend denial sets success = false with a non-secret message and drives the SDK’s denial path.

A single aureva::Api instance is used from one thread at a time for the mutating calls init() / license() / check(). Reading app.response and app.user_data from a different thread (for example a UI or render thread) is safe and non-blocking. For full details, see C++ SDK: Thread-Safety Contract.