.NET SDK Reference
Package: CpodSdk
NuGet: nuget.org/packages/CpodSdk
Source: github.com/cpod-ai/cpod-sdk/tree/main/sdks/dotnet
Target Frameworks: net6.0, net7.0, net8.0, netstandard2.1
Installation
dotnet add package CpodSdk<!-- Or in your .csproj -->
<PackageReference Include="CpodSdk" Version="1.*" />Client Initialization
using Cpod;
// Reads CPOD_API_KEY from environment variables
var client = new CpodClient();
// With explicit options
var client = new CpodClient(new CpodOptions
{
ApiKey = Environment.GetEnvironmentVariable("CPOD_API_KEY")
?? throw new InvalidOperationException("CPOD_API_KEY is required"),
BaseUrl = new Uri("https://api.cyberpod.app/v1"),
Timeout = TimeSpan.FromSeconds(30),
MaxRetries = 3,
});CpodClient implements IDisposable. For long-lived applications, register it as a singleton:
// In Program.cs / Startup.cs (ASP.NET Core)
builder.Services.AddSingleton<CpodClient>();
// or with configuration
builder.Services.AddSingleton(sp => new CpodClient(new CpodOptions
{
ApiKey = builder.Configuration["CpodSdk:ApiKey"],
}));PodService — client.Pods
List pods
var result = await client.Pods.ListAsync(new PodListRequest
{
TenantId = "acme-corp",
Status = PodStatus.Running,
Region = "us-east-1",
Limit = 50,
}, cancellationToken);
foreach (var pod in result.Data)
{
Console.WriteLine($"{pod.Id}: {pod.Name} [{pod.Status}]");
}
// result.NextCursor — pass for next pageGet a pod
var pod = await client.Pods.GetAsync("pod_01jm8xk2y3z", cancellationToken);Create a pod
var pod = await client.Pods.CreateAsync(new PodCreateRequest
{
TenantId = "acme-corp",
Name = "my-worker",
Image = "cpod/worker:latest",
Cpu = 2.0,
MemoryMb = 4096,
Region = "us-east-1",
Env = new Dictionary<string, string> { ["NODE_ENV"] = "production" },
Labels = new Dictionary<string, string> { ["team"] = "platform" },
}, cancellationToken);Update a pod
var pod = await client.Pods.UpdateAsync("pod_01jm8xk2y3z", new PodUpdateRequest
{
Name = "renamed-worker",
Labels = new Dictionary<string, string> { ["app"] = "worker-v2" },
}, cancellationToken);Delete a pod
await client.Pods.DeleteAsync("pod_01jm8xk2y3z", cancellationToken);Lifecycle operations
await client.Pods.StartAsync("pod_01jm8xk2y3z", cancellationToken);
await client.Pods.StopAsync("pod_01jm8xk2y3z", new PodStopRequest
{
GracePeriodSeconds = 30,
}, cancellationToken);
await client.Pods.RestartAsync("pod_01jm8xk2y3z", cancellationToken);Stream logs
await foreach (var line in client.Pods.StreamLogsAsync("pod_01jm8xk2y3z", new PodLogsRequest
{
Follow = true,
Tail = 100,
}, cancellationToken))
{
Console.WriteLine(line);
}Auto-paginated IAsyncEnumerable
await foreach (var pod in client.Pods.ListAllAsync(new PodListRequest
{
TenantId = "acme-corp",
}, cancellationToken))
{
await ProcessPodAsync(pod);
}TenantService — client.Tenants
// List
var tenants = await client.Tenants.ListAsync(new TenantListRequest { Limit = 50 }, ct);
// Get
var tenant = await client.Tenants.GetAsync("acme-corp", ct);
// Create
var tenant = await client.Tenants.CreateAsync(new TenantCreateRequest
{
Id = "acme-corp",
Name = "Acme Corporation",
Plan = TenantPlan.Enterprise,
Region = "us-east-1",
Metadata = new Dictionary<string, string> { ["salesforce_id"] = "SF-001234" },
}, ct);
// Update
var tenant = await client.Tenants.UpdateAsync("acme-corp", new TenantUpdateRequest
{
Name = "Acme Corp (Updated)",
}, ct);
// Member management
await client.Tenants.AddMemberAsync("acme-corp", new AddMemberRequest
{
UserId = "user_123",
Role = TenantRole.Admin,
}, ct);
await client.Tenants.RemoveMemberAsync("acme-corp", "user_123", ct);
// Policy
await client.Tenants.SetPolicyAsync("acme-corp", new TenantPolicy
{
MaxPods = 100,
AllowedRegions = new[] { "us-east-1", "eu-west-1" },
RequireLabels = new[] { "team", "env" },
IpAllowlist = new[] { "10.0.0.0/8" },
}, ct);EventService — client.Events
Query events
var result = await client.Events.ListAsync(new EventListRequest
{
TenantId = "acme-corp",
Type = "pod.started",
Since = DateTimeOffset.UtcNow.AddDays(-1),
Limit = 100,
}, ct);SSE subscription
await foreach (var evt in client.Events.SubscribeAsync(new EventSubscribeRequest
{
TenantId = "acme-corp",
Types = new[] { "pod.started", "pod.stopped", "pod.error" },
}, ct))
{
Console.WriteLine($"[{evt.Timestamp:u}] {evt.Type}: {evt.ResourceId}");
if (evt.Type == "pod.error")
await AlertOnCallAsync(evt);
}WebSocket subscription
using var ws = await client.Events.ConnectWebSocketAsync(new EventSubscribeRequest
{
TenantId = "acme-corp",
Types = new[] { "pod.*" },
}, ct);
await foreach (var evt in ws.ReceiveAsync(ct))
{
Console.WriteLine(System.Text.Json.JsonSerializer.Serialize(evt));
}Record Types
All response models are C# record types with init-only properties.
public sealed record Pod
{
public required string Id { get; init; }
public required string TenantId { get; init; }
public required string Name { get; init; }
public required PodStatus Status { get; init; }
public required string Image { get; init; }
public required double Cpu { get; init; }
public required int MemoryMb { get; init; }
public required string Region { get; init; }
public IReadOnlyDictionary<string, string> Env { get; init; } = new Dictionary<string, string>();
public IReadOnlyDictionary<string, string> Labels { get; init; } = new Dictionary<string, string>();
public required DateTimeOffset CreatedAt { get; init; }
public required DateTimeOffset UpdatedAt { get; init; }
public DateTimeOffset? StartedAt { get; init; }
public DateTimeOffset? StoppedAt { get; init; }
}
public enum PodStatus { Pending, Running, Stopped, Error, Terminating }Error Handling
using Cpod.Errors;
try
{
var pod = await client.Pods.GetAsync("pod_nonexistent", ct);
}
catch (NotFoundException ex)
{
Console.WriteLine($"Not found: {ex.Message}");
}
catch (ValidationException ex)
{
foreach (var (field, msg) in ex.Fields)
Console.WriteLine($" {field}: {msg}");
}
catch (AuthException ex)
{
Console.WriteLine($"Auth error ({ex.Status}): {ex.Message}");
}
catch (RateLimitException ex)
{
Console.WriteLine($"Rate limited. Retry after {ex.RetryAfter}s");
await Task.Delay(TimeSpan.FromSeconds(ex.RetryAfter), ct);
}
catch (CpodException ex)
{
Console.WriteLine($"API error {ex.Status} [{ex.Code}]: {ex.Message}");
}All *Async methods accept an optional CancellationToken. Pass your request’s cancellation token
to propagate graceful cancellation through to the HTTP layer.
Dependency Injection (ASP.NET Core)
// Program.cs
builder.Services.AddHttpClient<CpodClient>();
builder.Services.Configure<CpodOptions>(builder.Configuration.GetSection("CpodSdk"));
builder.Services.AddSingleton(sp =>
{
var opts = sp.GetRequiredService<IOptions<CpodOptions>>().Value;
return new CpodClient(opts);
});
// appsettings.json
{
"CpodSdk": {
"ApiKey": "cpod_live_xxx",
"BaseUrl": "https://api.cyberpod.app/v1"
}
}