PlanSolve 0.29.0
dotnet add package PlanSolve --version 0.29.0
NuGet\Install-Package PlanSolve -Version 0.29.0
<PackageReference Include="PlanSolve" Version="0.29.0" />
<PackageVersion Include="PlanSolve" Version="0.29.0" />
<PackageReference Include="PlanSolve" />
paket add PlanSolve --version 0.29.0
#r "nuget: PlanSolve, 0.29.0"
#:package PlanSolve@0.29.0
#addin nuget:?package=PlanSolve&version=0.29.0
#tool nuget:?package=PlanSolve&version=0.29.0
PlanSolve for .NET
Official .NET client for the PlanSolve optimization API. One typed client covers three solvers (field service routing, professional-services task assignment, and shift scheduling) with async/await, built-in polling, and clean error messages.
Installation
dotnet add package PlanSolve
Targets .NET 10.
Quick start
using PlanSolve;
using PlanSolve.FieldService;
using var client = new PlanSolveClient("YOUR_API_KEY");
var request = new FieldServiceStartRequest
{
Vehicles =
{
new Vehicle
{
Id = "tech1",
Location = [40.7128, -74.0060],
Skills = ["repair"],
Shifts = [new Shift(DateTime.Parse("2026-04-02T08:00:00"), DateTime.Parse("2026-04-02T17:00:00"))],
},
},
Visits =
{
new Visit
{
Id = "visit1",
Name = "AC Repair - Downtown Office",
Location = [40.7589, -73.9851],
ServiceDuration = Duration.FromMinutes(60),
Priority = "HIGH",
RequiredSkills = ["repair"],
},
},
};
// Submit and await the optimized plan in a single call
var result = await client.FieldService.StartAndWaitForCompletionAsync(request);
foreach (var vehicle in result.Vehicles)
Console.WriteLine($"Vehicle {vehicle.Id}: {vehicle.Visits.Count} visits");
Solvers
One client, three solvers. All share the same submit, poll, result workflow:
| Solver | Accessor | Use for |
|---|---|---|
| Field Service | client.FieldService |
Vehicle routing with travel time, time windows, and skills |
| Professional Services | client.ProfessionalServices |
Task assignment by skill, availability, priority, and deadlines |
| Shift | client.Shift |
Shift scheduling across contracts, availability, and fairness |
Every accessor exposes the same methods:
| Method | HTTP | Returns |
|---|---|---|
StartAsync(request) |
POST /api/v1/{solver} |
Start response with the JobId |
GetStatusAsync(jobId) |
GET /api/v1/{solver}/{jobId}/status |
SolverStatusResponse |
GetResultAsync(jobId) |
GET /api/v1/{solver}/{jobId} |
The solver's result type |
StopAsync(jobId) |
DELETE /api/v1/{solver}/{jobId} |
The best solution found so far (same type as GetResultAsync) |
GetAnalysisAsync(jobId) |
GET /api/v1/{solver}/{jobId}/analyze |
AnalysisResponse (constraint breakdown) |
WaitForCompletionAsync(jobId, ...) |
polls status, then fetches the result | The solver's result type |
StartAndWaitForCompletionAsync(request, ...) |
start + wait | The solver's result type |
GetStatusAsync, GetResultAsync, StopAsync and GetAnalysisAsync also have an overload that takes a CancellationToken.
// Stop a long-running solve early and keep the best plan found so far
var best = await client.FieldService.StopAsync(jobId);
// Explain the score: which constraints were broken, and by what
var analysis = await client.FieldService.GetAnalysisAsync(jobId);
Polling
WaitForCompletionAsync and StartAndWaitForCompletionAsync poll the status endpoint every pollIntervalMs milliseconds, up to maxAttempts times. The defaults are 5000 ms x 150 attempts (12.5 minutes), which covers the server's 10 minute solve cap with headroom. Passing a value of 0 or less uses the default.
A job is complete when the status reports Solving == false and SolverStatus == NOT_SOLVING. The result is then fetched with GetResultAsync. Status polls and result fetches are retried on failure (up to 3 retries with 2, 4 and 8 second backoff) before the error is thrown. StopAsync is not retried. The library never writes to the console.
Configuration
Pass your API key to the constructor: new PlanSolveClient("...") (an overload accepts a custom HttpClient). It is sent as the X-API-KEY header on every request. PlanSolveClient is IDisposable, so wrap it in using.
Error handling
| Exception | When |
|---|---|
HttpRequestException |
The API returned a non-2xx status. .StatusCode is populated and the message is readable, e.g. Request failed with status code 400 (BadRequest): vehicles: At least one vehicle is required. A failed solve answers the status endpoint with 422, which surfaces here while waiting. |
ArgumentException |
jobId is null or empty (message: jobId cannot be null or empty. Pass the JobId returned by StartAsync., ParamName is jobId). |
TimeoutException |
The solver is still running after maxAttempts polls (message: Solver still running after N polls; raise maxAttempts or lower options.spentLimit.). |
OperationCanceledException |
The CancellationToken you passed was cancelled (may be the TaskCanceledException subtype). Cancellations are never retried. |
System.Text.Json.JsonException |
A response body could not be deserialized. The message includes the JSON path and a truncated copy of the body. |
try
{
var result = await client.FieldService.StartAndWaitForCompletionAsync(request);
}
catch (HttpRequestException e)
{
Console.WriteLine($"API error {(int?)e.StatusCode}: {e.Message}");
}
catch (TimeoutException e)
{
Console.WriteLine(e.Message);
}
Documentation
Full guides, per-solver data models, and parameter reference live on the docs site:
- Field Service: https://getplansolve.com/docs/fieldservice/sdk/dotnet
- Professional Services: https://getplansolve.com/docs/professionalservices/sdk/dotnet
- Shift: https://getplansolve.com/docs/shiftsolver/sdk/dotnet
Package: NuGet
License
Apache-2.0
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. 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. |
-
net10.0
- Polly (>= 8.6.5)
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 |
|---|---|---|
| 0.29.0 | 90 | 9/22/2026 |
| 0.28.0 | 89 | 9/22/2026 |
| 0.27.0 | 126 | 7/23/2026 |
| 0.26.0 | 115 | 7/22/2026 |
| 0.25.8 | 122 | 7/22/2026 |
| 0.25.7 | 112 | 7/21/2026 |
| 0.25.6 | 111 | 7/21/2026 |
| 0.25.5 | 117 | 7/21/2026 |
| 0.25.4 | 116 | 7/21/2026 |
| 0.25.3 | 109 | 7/21/2026 |
| 0.25.2 | 114 | 7/21/2026 |
| 0.25.1 | 106 | 7/21/2026 |
| 0.25.0 | 113 | 7/21/2026 |