The official C++ SDK for TofuPilot. Integrate your hardware test runs into one app with just a few lines of C++.
Add to your CMakeLists.txt:
include(FetchContent)
FetchContent_Declare(tofupilot GIT_REPOSITORY https://github.com/tofupilot/cpp.git GIT_TAG v2.12.0 GIT_SHALLOWTRUE)
FetchContent_MakeAvailable(tofupilot)
target_link_libraries(your_targetPRIVATEtofupilot)Requires: C++17, OpenSSL
#include<tofupilot/tofupilot.hpp>
#include<iostream>intmain() {
auto client = tofupilot::TofuPilot("your-api-key");
auto run = client.runs().create()
.procedure_id("your-procedure-id")
.serial_number("SN-001234")
.part_number("PCB-V1.2")
.outcome(tofupilot::Outcome::Pass)
.started_at("2025-01-01T00:00:00Z")
.ended_at("2025-01-01T00:05:00Z")
.send();
std::cout << "Run created: " << run.id << std::endl;
}Set your API key as an environment variable:
export TOFUPILOT_API_KEY="your-api-key"auto client = tofupilot::TofuPilot(std::getenv("TOFUPILOT_API_KEY"));Or pass it directly:
auto client = tofupilot::TofuPilot("your-api-key");To point to a different server (e.g. self-hosted):
auto client = tofupilot::TofuPilot(
tofupilot::ClientConfig::with_api_key("your-api-key")
.set_base_url("https://your-instance.example.com")
);| Resource | Operations |
|---|---|
client.procedures() | create, list, get, delete_, update |
client.versions() | get, delete_, create |
client.runs() | create, list, delete_, get, update, create_attachment, update_metadata |
client.attachments() | initialize, finalize |
client.units() | create, list, delete_, get, update, add_child, remove_child, create_attachment, delete_attachment |
client.parts() | create, list, get, update, delete_ |
client.revisions() | get, update, delete_, create |
client.batches() | get, delete_, update, list, create |
client.stations() | create, list, get_current, get, update, remove |
client.users() | list |
client.imports() | structured, tabular |
client.logs() | list, get |
client.phases() | list, get |
client.measurements() | list, get |
client.deployments() | list, get |
tofupilot::RunCreateMeasurements m;
m.name = "Output Voltage";
m.outcome = tofupilot::ValidatorsOutcome::Pass;
m.measured_value = nlohmann::json(3.3);
tofupilot::RunCreatePhases phase;
phase.name = "Voltage Test";
phase.outcome = tofupilot::PhasesOutcome::Pass;
phase.started_at = "2025-01-01T00:00:00Z";
phase.ended_at = "2025-01-01T00:05:00Z";
phase.measurements = {m};
auto run = client.runs().create()
.procedure_id("your-procedure-id")
.serial_number("SN-001")
.part_number("PCB-V1")
.outcome(tofupilot::Outcome::Pass)
.started_at("2025-01-01T00:00:00Z")
.ended_at("2025-01-01T00:05:00Z")
.phases({phase})
.send();auto result = client.runs().list()
.part_numbers({"PCB-V1"})
.outcomes({tofupilot::Outcome::Pass})
.limit(10)
.send();
for (constauto& run : result.data) {
std::cout << run.id << " — " << run.unit.serial_number << std::endl;
}// Upload a fileauto upload = tofupilot::upload_file(client, "report.pdf");
// Link to a run
client.runs().update().id(run.id).attachments({upload.id}).send();
// Downloadtofupilot::download_file(upload.url, "local-copy.pdf");try {
auto run = client.runs().get().id("nonexistent").send();
} catch (const tofupilot::NotFoundError& e) {
std::cerr << "Not found: " << e.error().message << std::endl;
} catch (const tofupilot::BadRequestError& e) {
for (constauto& issue : e.error().issues)
std::cerr << " - " << issue.message << std::endl;
} catch (const tofupilot::ApiException& e) {
std::cerr << "API error " << e.status_code() << ": " << e.what() << std::endl;
}| Exception | Status Code |
|---|---|
BadRequestError | 400 |
UnauthorizedError | 401 |
ForbiddenError | 403 |
NotFoundError | 404 |
ConflictError | 409 |
UnprocessableContentError | 422 |
InternalServerError | 500 |
TofuPilot is not thread-safe. Use one client per thread or synchronize externally.
MIT