C++ examples — Ludex ingestion
Game servers and native tools often call Ludex over HTTPS with a small JSON payload. Below: a libcurl example you can drop into a server build, plus notes for Unreal Engine (FHttpModule).
Paths and JSON match the live API: POST /v1/ingest/event, POST /v1/ingest/batch, Authorization: Bearer, Content-Type: application/json. Success is HTTP 202.
Prerequisites (libcurl)
- Link libcurl and ensure TLS backend is configured for
https://in production. - Build your JSON string however you prefer (
std::format, manual concatenation, nlohmann/json, RapidJSON, etc.).
libcurl — single event
Replace string literals with your real project_id, environment (must match the API key’s environment id), and API_KEY.
#include <curl/curl.h>
#include <string>
#include <iostream>
static size_t write_cb(char* ptr, size_t size, size_t nmemb, void* userdata) {
auto* out = static_cast<std::string*>(userdata);
out->append(ptr, size * nmemb);
return size * nmemb;
}
int main() {
const char* base_url = "https://ingest.ludexstudio.com/v1/ingest/event";
const char* api_key = "YOUR_API_KEY";
// Minimal valid body: ISO-8601 timestamp, event_name, properties object.
const std::string json = R"({
"project_id": "YOUR_PROJECT_ID",
"environment": "YOUR_ENVIRONMENT_ID",
"event": {
"event_name": "server_match_started",
"timestamp": "2026-04-13T12:00:00.000Z",
"session_id": "sess-native-1",
"properties": { "map": "arena_01" },
"sdk": { "name": "cpp-libcurl-example", "version": "1.0.0" }
}
})";
CURL* curl = curl_easy_init();
if (!curl) return 1;
std::string response_body;
struct curl_slist* headers = nullptr;
headers = curl_slist_append(headers, "Content-Type: application/json");
std::string auth_hdr = std::string("Authorization: Bearer ") + api_key;
headers = curl_slist_append(headers, auth_hdr.c_str());
headers = curl_slist_append(headers, "Idempotency-Key: cpp-demo-001");
headers = curl_slist_append(headers, "X-Correlation-Id: corr-cpp-001");
curl_easy_setopt(curl, CURLOPT_URL, base_url);
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, json.c_str());
curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, static_cast<long>(json.size()));
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_cb);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response_body);
CURLcode res = curl_easy_perform(curl);
long http_code = 0;
if (res == CURLE_OK)
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http_code);
curl_slist_free_all(headers);
curl_easy_cleanup(curl);
std::cout << "http=" << http_code << "\n" << response_body << "\n";
return (res != CURLE_OK || http_code != 202) ? 1 : 0;
}
Compile (example flags vary by platform):
c++ -std=c++17 ingest_example.cpp -lcurl -o ingest_example
libcurl — batch
Same pattern: POST {base}/v1/ingest/batch with body:
{
"project_id": "YOUR_PROJECT_ID",
"environment": "YOUR_ENVIRONMENT_ID",
"events": [
{
"event_name": "tick",
"timestamp": "2026-04-13T12:00:01.000Z",
"properties": { "tps": 60 }
}
]
}
Requires scope ingest:batch. Default max 5000 events per request.
Retries
On 429 or 5xx, sleep with exponential backoff and retry the same logical event with the same event_id (if you include one). Do not blindly retry 401, 403, 422, or 413.
Unreal Engine (FHttpModule)
For game clients, Unreal’s FHttpModule::Get().CreateRequest() is the usual transport:
SetURL(FString::Printf(TEXT("%s/v1/ingest/event"), *BaseUrl))SetVerb(TEXT("POST"))SetHeader(TEXT("Authorization"), FString::Printf(TEXT("Bearer %s"), *ApiKey))SetHeader(TEXT("Content-Type"), TEXT("application/json"))- Optional:
Idempotency-Key,X-Correlation-Id,X-Request-Id SetContentAsString(JsonBody)thenProcessRequest()
Reuse the same JSON field names as in contract-reference.md. A first-party Ludex Unreal SDK is planned (not shipped in this repo yet); for the pilot, keep transport in your game or server code with the same /v1/ingest/* contract, retries, and idempotency rules as in the C++ retries section above.