C++ Implementation
Drop-in license validation for Windows apps. Copy the SDK files into your project, plug in your App ID and App Token from the dashboard, and call panel.license(key) at startup.
https://www.keypanel.ccQuick start
Add keypanel.hpp and keypanel.cpp to your project (sources below), then:
main.cpp
#include "keypanel.hpp"
KeyPanel::api panel(
"https://www.keypanel.cc",
"your-app-id", // Dashboard → Application → App ID
"your-app-token" // Dashboard → Application → App Token
);
panel.set_client_version("1.0.0");
if (!panel.license("LIC-XXXXXX-XXXXXX-XXXXXX")) {
// panel.response.message has the error
// update_required → panel.response.update_url
return 1;
}
// panel.response.expires_at — ISO timestamp when set
// Your protected app logic starts hereAPI
| Method | Description |
|---|---|
| license(key) | Validate on this device; auto-activate if not yet bound |
| activate(key) | Bind license to this device (HWID) |
| validate(key) | Check license is still valid on this device |
| set_client_version(ver) | Send build version on every request (e.g. "3.1") |
| get_device_id() | Windows MachineGuid used as HWID |
| set_device_id(id) | Override HWID for testing |
After each call, read panel.response for success, message, expires_at, activated, already_active, and on force-update: reason, min_client_version, update_url.
Credentials
| Dashboard | SDK argument |
|---|---|
| Deploy URL | base_url |
| App ID | app_id |
| App Token | app_token |
Integration steps
- Copy
keypanel.hppandkeypanel.cppinto your project. - Add
keypanel.cppto your build. - WinHTTP is linked automatically via
#pragma commentin the source. - Obfuscate your app token in release builds.
Flow
App launch ↓ panel.license(user_key) ↓ POST /api/client/validate → valid? → run app ↓ (device not activated) POST /api/client/activate → bind HWID, start subscription clock
Users claim keys and manage accounts in the launcher. Your client only needs activate + validate — the SDK handles both via license().
SDK source
include/keypanel.hpp
#pragma once
#include <string>
namespace KeyPanel {
struct Response {
bool success = false;
std::string message;
std::string expires_at;
bool already_active = false;
bool activated = false;
std::string reason;
std::string min_client_version;
std::string latest_client_version;
std::string update_url;
};
// Reads Windows MachineGuid from the registry (HWID). Falls back to computer name.
std::string get_device_id();
class api {
public:
api(std::string base_url, std::string app_id, std::string app_token);
void set_device_id(std::string device_id);
const std::string& device_id() const;
// Optional build version sent on every activate/validate (e.g. "3.1" or "v3.1.0").
void set_client_version(std::string version);
const std::string& client_version() const;
// Validate on this device; activates automatically if not yet bound.
bool license(const std::string& license_key);
bool activate(const std::string& license_key);
bool validate(const std::string& license_key);
Response response;
private:
std::string base_url_;
std::string app_id_;
std::string app_token_;
std::string device_id_;
std::string client_version_;
void reset_response();
void fill_version_fields(const std::string& raw);
bool post_client(const wchar_t* path, const std::string& license_key, std::string& raw);
};
} // namespace KeyPanel
src/keypanel.cpp
#include "keypanel.hpp"
#include <Windows.h>
#include <winhttp.h>
#include <cctype>
#include <sstream>
#include <vector>
#pragma comment(lib, "winhttp.lib")
namespace KeyPanel {
namespace {
std::string json_escape(const std::string& value) {
std::string out;
out.reserve(value.size() + 8);
for (char c : value) {
switch (c) {
case '\\': out += "\\\\"; break;
case '"': out += "\\\""; break;
case '\n': out += "\\n"; break;
case '\r': out += "\\r"; break;
case '\t': out += "\\t"; break;
default: out += c; break;
}
}
return out;
}
std::string extract_json_string(const std::string& json, const std::string& key) {
const std::string needle = "\"" + key + "\"";
size_t pos = json.find(needle);
if (pos == std::string::npos) return "";
pos = json.find(':', pos + needle.size());
if (pos == std::string::npos) return "";
pos = json.find('"', pos);
if (pos == std::string::npos) return "";
++pos;
std::string out;
while (pos < json.size()) {
char c = json[pos++];
if (c == '"') break;
if (c == '\\' && pos < json.size()) {
char esc = json[pos++];
switch (esc) {
case '"': out += '"'; break;
case '\\': out += '\\'; break;
case 'n': out += '\n'; break;
case 'r': out += '\r'; break;
case 't': out += '\t'; break;
default: out += esc; break;
}
} else {
out += c;
}
}
return out;
}
bool json_has_true(const std::string& json, const std::string& key) {
const std::string needle = "\"" + key + "\":true";
return json.find(needle) != std::string::npos;
}
bool parse_url(
const std::string& base_url,
std::wstring& host,
bool& https,
INTERNET_PORT& port,
std::wstring& base_path
) {
std::string url = base_url;
https = false;
port = 80;
if (url.rfind("https://", 0) == 0) {
https = true;
port = 443;
url = url.substr(8);
} else if (url.rfind("http://", 0) == 0) {
url = url.substr(7);
}
const size_t slash = url.find('/');
const std::string host_port = slash == std::string::npos ? url : url.substr(0, slash);
base_path = slash == std::string::npos ? L"" : std::wstring(url.begin() + static_cast<ptrdiff_t>(slash), url.end());
const size_t colon = host_port.find(':');
const std::string host_str = colon == std::string::npos ? host_port : host_port.substr(0, colon);
if (colon != std::string::npos) {
port = static_cast<INTERNET_PORT>(std::stoi(host_port.substr(colon + 1)));
}
host = std::wstring(host_str.begin(), host_str.end());
return !host.empty();
}
bool http_post_json(
const std::wstring& host,
bool https,
INTERNET_PORT port,
const std::wstring& path,
const std::string& body,
std::string& response,
std::string& error
) {
HINTERNET session = WinHttpOpen(
L"KeyPanelSDK/1.0",
WINHTTP_ACCESS_TYPE_DEFAULT_PROXY,
WINHTTP_NO_PROXY_NAME,
WINHTTP_NO_PROXY_BYPASS,
0
);
if (!session) {
error = "WinHttpOpen failed.";
return false;
}
HINTERNET connect = WinHttpConnect(session, host.c_str(), port, 0);
if (!connect) {
WinHttpCloseHandle(session);
error = "WinHttpConnect failed.";
return false;
}
const DWORD flags = https ? WINHTTP_FLAG_SECURE : 0;
HINTERNET request = WinHttpOpenRequest(
connect,
L"POST",
path.c_str(),
nullptr,
WINHTTP_NO_REFERER,
WINHTTP_DEFAULT_ACCEPT_TYPES,
flags
);
if (!request) {
WinHttpCloseHandle(connect);
WinHttpCloseHandle(session);
error = "WinHttpOpenRequest failed.";
return false;
}
const wchar_t* headers = L"Content-Type: application/json\r\nAccept: application/json\r\n";
BOOL ok = WinHttpSendRequest(
request,
headers,
static_cast<DWORD>(-1),
const_cast<LPVOID>(static_cast<LPCVOID>(body.data())),
static_cast<DWORD>(body.size()),
static_cast<DWORD>(body.size()),
0
);
if (!ok) {
WinHttpCloseHandle(request);
WinHttpCloseHandle(connect);
WinHttpCloseHandle(session);
error = "WinHttpSendRequest failed.";
return false;
}
ok = WinHttpReceiveResponse(request, nullptr);
if (!ok) {
WinHttpCloseHandle(request);
WinHttpCloseHandle(connect);
WinHttpCloseHandle(session);
error = "WinHttpReceiveResponse failed.";
return false;
}
response.clear();
DWORD available = 0;
do {
if (!WinHttpQueryDataAvailable(request, &available)) break;
if (available == 0) break;
std::vector<char> chunk(available);
DWORD read = 0;
if (!WinHttpReadData(request, chunk.data(), available, &read)) break;
response.append(chunk.data(), read);
} while (available > 0);
WinHttpCloseHandle(request);
WinHttpCloseHandle(connect);
WinHttpCloseHandle(session);
return true;
}
std::string reason_to_message(const std::string& reason) {
if (reason == "not_found") return "License not found.";
if (reason == "expired") return "License expired.";
if (reason == "revoked") return "License revoked.";
if (reason == "device_not_activated") return "Device not activated.";
if (reason == "update_required") {
return "Update required. Please install the latest version.";
}
if (reason == "organization_disabled") return "Organization disabled.";
if (reason.empty()) return "License is not valid on this device.";
return "License invalid: " + reason + ".";
}
} // namespace
std::string get_device_id() {
HKEY key = nullptr;
if (RegOpenKeyExA(
HKEY_LOCAL_MACHINE,
"SOFTWARE\\Microsoft\\Cryptography",
0,
KEY_READ | KEY_WOW64_64KEY,
&key
) == ERROR_SUCCESS) {
char guid[128]{};
DWORD size = sizeof(guid);
if (RegQueryValueExA(
key,
"MachineGuid",
nullptr,
nullptr,
reinterpret_cast<LPBYTE>(guid),
&size
) == ERROR_SUCCESS) {
RegCloseKey(key);
return std::string(guid);
}
RegCloseKey(key);
}
char name[MAX_COMPUTERNAME_LENGTH + 1]{};
DWORD len = MAX_COMPUTERNAME_LENGTH + 1;
if (GetComputerNameA(name, &len)) {
return std::string(name);
}
return "unknown-device";
}
api::api(std::string base_url, std::string app_id, std::string app_token)
: base_url_(std::move(base_url)),
app_id_(std::move(app_id)),
app_token_(std::move(app_token)),
device_id_(get_device_id()) {}
void api::set_device_id(std::string device_id) {
device_id_ = std::move(device_id);
}
const std::string& api::device_id() const {
return device_id_;
}
void api::set_client_version(std::string version) {
client_version_ = std::move(version);
}
const std::string& api::client_version() const {
return client_version_;
}
void api::reset_response() {
response = Response{};
}
void api::fill_version_fields(const std::string& raw) {
response.reason = extract_json_string(raw, "reason");
response.min_client_version = extract_json_string(raw, "minClientVersion");
response.latest_client_version = extract_json_string(raw, "latestClientVersion");
response.update_url = extract_json_string(raw, "updateUrl");
}
bool api::post_client(const wchar_t* path, const std::string& license_key, std::string& raw) {
std::ostringstream body;
body << "{\"appId\":\"" << json_escape(app_id_) << "\","
<< "\"appToken\":\"" << json_escape(app_token_) << "\","
<< "\"licenseKey\":\"" << json_escape(license_key) << "\","
<< "\"deviceId\":\"" << json_escape(device_id_) << "\"";
if (!client_version_.empty()) {
body << ",\"clientVersion\":\"" << json_escape(client_version_) << "\"";
}
body << "}";
std::wstring host;
std::wstring base_path;
bool https = false;
INTERNET_PORT port = 80;
if (!parse_url(base_url_, host, https, port, base_path)) {
response.message = "Invalid api base URL.";
return false;
}
const std::wstring full_path = base_path + path;
return http_post_json(host, https, port, full_path, body.str(), raw, response.message);
}
bool api::activate(const std::string& license_key) {
reset_response();
std::string raw;
if (!post_client(L"/api/client/activate", license_key, raw)) {
return false;
}
fill_version_fields(raw);
if (!json_has_true(raw, "ok")) {
if (response.reason == "update_required") {
response.message = reason_to_message(response.reason);
const std::string server_msg = extract_json_string(raw, "message");
if (!server_msg.empty()) response.message = server_msg;
return false;
}
response.message = extract_json_string(raw, "error");
if (response.message.empty()) response.message = "Activation failed.";
return false;
}
response.success = true;
response.already_active = json_has_true(raw, "alreadyActive");
response.activated = json_has_true(raw, "activated");
response.expires_at = extract_json_string(raw, "expiresAt");
if (response.already_active) {
response.message = "Already active on this device.";
} else if (response.activated) {
response.message = "Device activated.";
} else {
response.message = "Activation successful.";
}
return true;
}
bool api::validate(const std::string& license_key) {
reset_response();
std::string raw;
if (!post_client(L"/api/client/validate", license_key, raw)) {
return false;
}
fill_version_fields(raw);
if (!json_has_true(raw, "ok")) {
response.message = extract_json_string(raw, "error");
if (response.message.empty()) response.message = "Validation request failed.";
return false;
}
if (!json_has_true(raw, "valid")) {
if (response.reason.empty()) {
response.reason = extract_json_string(raw, "reason");
}
if (response.reason == "update_required") {
const std::string server_msg = extract_json_string(raw, "message");
response.message = server_msg.empty() ? reason_to_message(response.reason) : server_msg;
} else {
response.message = reason_to_message(response.reason);
}
return false;
}
response.success = true;
response.expires_at = extract_json_string(raw, "expiresAt");
response.message = "License valid.";
return true;
}
bool api::license(const std::string& license_key) {
if (validate(license_key)) {
return true;
}
if (response.reason == "update_required") {
return false;
}
const std::string last_message = response.message;
if (last_message.find("Device not activated") == std::string::npos &&
last_message.find("device_not_activated") == std::string::npos) {
return false;
}
return activate(license_key);
}
} // namespace KeyPanel
Example project
example/main.cpp
#include "keypanel.hpp"
#include <iostream>
#include <string>
int main() {
// Credentials from Key Panel dashboard → your Application.
// Prefer downloading the per-app SDK zip (credentials prefilled).
const std::string base_url = "https://keypanel.cc";
const std::string app_id = "your-app-id";
const std::string app_token = "your-app-token";
KeyPanel::api panel(base_url, app_id, app_token);
panel.set_client_version("1.0.0"); // match your build; required if the app sets a minimum
std::cout << "Device ID: " << panel.device_id() << "\n";
std::cout << "Enter license key: ";
std::string license_key;
std::getline(std::cin, license_key);
if (!panel.license(license_key)) {
std::cerr << "Failed: " << panel.response.message << "\n";
if (panel.response.reason == "update_required") {
if (!panel.response.update_url.empty()) {
std::cerr << "Update: " << panel.response.update_url << "\n";
}
}
return 1;
}
std::cout << "OK: " << panel.response.message << "\n";
if (!panel.response.expires_at.empty()) {
std::cout << "Expires: " << panel.response.expires_at << "\n";
}
// Your protected app logic starts here.
return 0;
}
CMakeLists.txt
cmake_minimum_required(VERSION 3.16) project(keypanel_sdk LANGUAGES CXX) set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) add_library(keypanel STATIC src/keypanel.cpp ) target_include_directories(keypanel PUBLIC include) add_executable(keypanel_example example/main.cpp) target_link_libraries(keypanel_example PRIVATE keypanel)
Download SDK
Zip archive with everything you need to get started.
include/keypanel.hppsrc/keypanel.cppCMakeLists.txtexample/main.cpp