TofuPilot 2.12.0

dotnet add package TofuPilot --version 2.12.0
                    
NuGet\Install-Package TofuPilot -Version 2.12.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="TofuPilot" Version="2.12.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="TofuPilot" Version="2.12.0" />
                    
Directory.Packages.props
<PackageReference Include="TofuPilot" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add TofuPilot --version 2.12.0
                    
#r "nuget: TofuPilot, 2.12.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package TofuPilot@2.12.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=TofuPilot&version=2.12.0
                    
Install as a Cake Addin
#tool nuget:?package=TofuPilot&version=2.12.0
                    
Install as a Cake Tool

TofuPilot C# SDK

License: MIT .NET Tests

The official C# SDK for TofuPilot. Integrate your hardware test runs into one app with just a few lines of C#.

Installation

Add a project reference:

dotnet add reference path/to/TofuPilot.csproj

Quick Start

using TofuPilot;
using TofuPilot.Models.Requests;

var client = new TofuPilot(apiKey: Environment.GetEnvironmentVariable("TOFUPILOT_API_KEY")!);

var run = await client.Runs.CreateAsync(new RunCreateRequest
{
    ProcedureId = "your-procedure-id",
    SerialNumber = "SN001",
    PartNumber = "PN001",
    Outcome = RunCreateOutcome.Pass,
    StartedAt = DateTime.UtcNow.AddMinutes(-5),
    EndedAt = DateTime.UtcNow,
});

Console.WriteLine($"Run created: {run.Id}");

All async methods support CancellationToken:

using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(10));
var run = await client.Runs.CreateAsync(request, cts.Token);

Authentication

Set your API key as an environment variable:

export TOFUPILOT_API_KEY="your-api-key"

Or pass it directly:

var client = new TofuPilot(apiKey: "your-api-key");

To point to a different server (e.g. self-hosted):

var client = new TofuPilot(
    apiKey: "your-api-key",
    serverUrl: "https://your-instance.com/api"
);

Custom certificates

using System.Security.Cryptography.X509Certificates;
using TofuPilot.Utils;

var handler = new HttpClientHandler();
handler.ClientCertificates.Add(new X509Certificate2("client.pfx", "password"));

var client = new TofuPilot(
    apiKey: "your-api-key",
    client: new TofuPilotHttpClient(handler)
);

Available Resources

Resource Operations
client.Runs List, Create, Get, Delete, Update
client.Runs.Attachments() UploadAsync, DownloadAsync
client.Units List, Create, Get, Delete, Update, AddChild, RemoveChild
client.Units.Attachments() UploadAsync, DownloadAsync, DeleteAsync
client.Parts List, Create, Get, Delete, Update
client.Parts.Revisions Create, Get, Delete, Update
client.Procedures List, Create, Get, Delete, Update
client.Procedures.Versions Create, Get, Delete
client.Batches List, Create, Get, Delete, Update
client.Stations List, Create, Get, GetCurrent, Remove, Update
client.User List

Usage Examples

Create a run with measurements

var run = await client.Runs.CreateAsync(new RunCreateRequest
{
    ProcedureId = procedureId,
    SerialNumber = "SN-001",
    PartNumber = "PCB-V1",
    Outcome = RunCreateOutcome.Pass,
    StartedAt = DateTime.UtcNow.AddMinutes(-5),
    EndedAt = DateTime.UtcNow,
    Phases = new List<RunCreatePhases>
    {
        new()
        {
            Name = "Voltage Test",
            Outcome = RunCreatePhasesOutcome.Pass,
            StartedAt = DateTime.UtcNow.AddMinutes(-5),
            EndedAt = DateTime.UtcNow,
            Measurements = new List<RunCreateMeasurements>
            {
                new()
                {
                    Name = "Output Voltage",
                    Outcome = RunCreateMeasurementsOutcome.Pass,
                    MeasuredValue = 3.3,
                    Units = RunCreateUnits.CreateStr("V"),
                    Validators = new List<RunCreateMeasurementsValidators>
                    {
                        new() { Operator = ">=", ExpectedValue = RunCreateMeasurementsExpectedValue.CreateNumber(3.0) },
                        new() { Operator = "<=", ExpectedValue = RunCreateMeasurementsExpectedValue.CreateNumber(3.6) },
                    },
                },
            },
        },
    },
});

List and filter runs

var result = await client.Runs.ListAsync(
    partNumbers: new List<string> { "PCB-V1" },
    outcomes: new List<RunListQueryParamOutcome> { RunListQueryParamOutcome.Pass },
    limit: 10
);

foreach (var run in result.Data)
    Console.WriteLine($"{run.Id} — {run.Unit.SerialNumber}");

Manage units and sub-units

// Create part and revision
await client.Parts.CreateAsync(new PartCreateRequest { Number = "PCB-V1", Name = "Main Board" });
await client.Parts.Revisions.CreateAsync("PCB-V1", new PartCreateRevisionRequestBody { Number = "REV-A" });

// Create units
await client.Units.CreateAsync(new UnitCreateRequest
{
    SerialNumber = "PARENT-001",
    PartNumber = "PCB-V1",
    RevisionNumber = "REV-A",
});
await client.Units.CreateAsync(new UnitCreateRequest
{
    SerialNumber = "CHILD-001",
    PartNumber = "PCB-V1",
    RevisionNumber = "REV-A",
});

// Link parent-child
await client.Units.AddChildAsync("PARENT-001", new UnitAddChildRequestBody
{
    ChildSerialNumber = "CHILD-001",
});

Attach files to runs and units

// Upload a file to a run
await client.Runs.Attachments().UploadAsync(runId, "report.pdf");

// Upload a file to a unit
await client.Units.Attachments().UploadAsync("SN-0001", "calibration.pdf");

// Download an attachment
var run = await client.Runs.GetAsync(runId);
await client.Runs.Attachments().DownloadAsync(run.Attachments[0].DownloadUrl, "local-copy.pdf");

// Delete a unit attachment
await client.Units.Attachments().DeleteAsync("SN-0001", new List<string> { attachmentId });

Error Handling

API errors throw typed exceptions:

using TofuPilot.Models.Errors;

try
{
    await client.Runs.GetAsync("nonexistent-id");
}
catch (NotFoundException ex)
{
    Console.WriteLine($"Not found: {ex.Message}");
}
catch (BadRequestException ex)
{
    Console.WriteLine($"Bad request: {ex.Message}");
}
catch (ApiException ex)
{
    Console.WriteLine($"API error {ex.StatusCode}: {ex.Body}");
}
Exception Status Code
BadRequestException 400
UnauthorizedException 401
ForbiddenException 403
NotFoundException 404
ConflictException 409
UnprocessableContentException 422
InternalServerErrorException 500
ApiException Any other

Running Tests

cd clients/csharp/tests
# Create .env.local with your API key and URL:
# TOFUPILOT_URL=http://localhost:3000
# TOFUPILOT_API_KEY_USER=your-api-key
dotnet test

Documentation

Acknowledgments

This package builds on the original C# SDK created by @Hylaean (versions 1.x).

License

MIT

Product Compatible and additional computed target framework versions.
.NET net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
  • net8.0

    • No dependencies.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
2.12.0 47 6/6/2026
2.11.4 103 5/29/2026
2.11.3 96 5/27/2026
2.7.1 101 5/10/2026
2.6.0 89 5/5/2026
2.3.4 106 4/16/2026
2.3.3 106 4/15/2026
2.3.2 100 4/6/2026
2.3.1 101 4/2/2026
2.3.0 106 4/1/2026
2.2.0 104 4/1/2026
2.0.2 97 3/31/2026
2.0.1 101 3/31/2026
1.6.3 309 2/18/2026
1.6.2 269 2/13/2026
1.6.1 123 2/13/2026
1.6.0 98 2/11/2026
1.6.0-beta.7 58 2/11/2026
1.6.0-beta.3 57 2/11/2026
1.5.0 178 2/10/2026
Loading failed