The official C# SDK for TofuPilot. Integrate your hardware test runs into one app with just a few lines of C#.
Add a project reference:
dotnet add reference path/to/TofuPilot.csprojusingTofuPilot;usingTofuPilot.Models.Requests;varclient=newTofuPilot(apiKey:Environment.GetEnvironmentVariable("TOFUPILOT_API_KEY")!);varrun=awaitclient.Runs.CreateAsync(newRunCreateRequest{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:
usingvarcts=newCancellationTokenSource(TimeSpan.FromSeconds(10));varrun=awaitclient.Runs.CreateAsync(request,cts.Token);Set your API key as an environment variable:
export TOFUPILOT_API_KEY="your-api-key"Or pass it directly:
varclient=newTofuPilot(apiKey:"your-api-key");To point to a different server (e.g. self-hosted):
varclient=newTofuPilot(apiKey:"your-api-key",serverUrl:"https://your-instance.com/api");usingSystem.Security.Cryptography.X509Certificates;usingTofuPilot.Utils;varhandler=newHttpClientHandler();handler.ClientCertificates.Add(newX509Certificate2("client.pfx","password"));varclient=newTofuPilot(apiKey:"your-api-key",client:newTofuPilotHttpClient(handler));| 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 |
varrun=awaitclient.Runs.CreateAsync(newRunCreateRequest{ProcedureId=procedureId,SerialNumber="SN-001",PartNumber="PCB-V1",Outcome=RunCreateOutcome.Pass,StartedAt=DateTime.UtcNow.AddMinutes(-5),EndedAt=DateTime.UtcNow,Phases=newList<RunCreatePhases>{new(){Name="Voltage Test",Outcome=RunCreatePhasesOutcome.Pass,StartedAt=DateTime.UtcNow.AddMinutes(-5),EndedAt=DateTime.UtcNow,Measurements=newList<RunCreateMeasurements>{new(){Name="Output Voltage",Outcome=RunCreateMeasurementsOutcome.Pass,MeasuredValue=3.3,Units=RunCreateUnits.CreateStr("V"),Validators=newList<RunCreateMeasurementsValidators>{new(){Operator=">=",ExpectedValue=RunCreateMeasurementsExpectedValue.CreateNumber(3.0)},new(){Operator="<=",ExpectedValue=RunCreateMeasurementsExpectedValue.CreateNumber(3.6)},},},},},},});varresult=awaitclient.Runs.ListAsync(partNumbers:newList<string>{"PCB-V1"},outcomes:newList<RunListQueryParamOutcome>{RunListQueryParamOutcome.Pass},limit:10);foreach(varruninresult.Data)Console.WriteLine($"{run.Id} — {run.Unit.SerialNumber}");// Create part and revisionawaitclient.Parts.CreateAsync(newPartCreateRequest{Number="PCB-V1",Name="Main Board"});awaitclient.Parts.Revisions.CreateAsync("PCB-V1",newPartCreateRevisionRequestBody{Number="REV-A"});// Create unitsawaitclient.Units.CreateAsync(newUnitCreateRequest{SerialNumber="PARENT-001",PartNumber="PCB-V1",RevisionNumber="REV-A",});awaitclient.Units.CreateAsync(newUnitCreateRequest{SerialNumber="CHILD-001",PartNumber="PCB-V1",RevisionNumber="REV-A",});// Link parent-childawaitclient.Units.AddChildAsync("PARENT-001",newUnitAddChildRequestBody{ChildSerialNumber="CHILD-001",});// Upload a file to a runawaitclient.Runs.Attachments().UploadAsync(runId,"report.pdf");// Upload a file to a unitawaitclient.Units.Attachments().UploadAsync("SN-0001","calibration.pdf");// Download an attachmentvarrun=awaitclient.Runs.GetAsync(runId);awaitclient.Runs.Attachments().DownloadAsync(run.Attachments[0].DownloadUrl,"local-copy.pdf");// Delete a unit attachmentawaitclient.Units.Attachments().DeleteAsync("SN-0001",newList<string>{attachmentId});API errors throw typed exceptions:
usingTofuPilot.Models.Errors;try{awaitclient.Runs.GetAsync("nonexistent-id");}catch(NotFoundExceptionex){Console.WriteLine($"Not found: {ex.Message}");}catch(BadRequestExceptionex){Console.WriteLine($"Bad request: {ex.Message}");}catch(ApiExceptionex){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 |
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 testThis package builds on the original C# SDK created by @Hylaean (versions 1.x).
MIT