Go SDK Reference

Module: github.com/cpod-ai/cpod-go
pkg.go.dev: pkg.go.dev/github.com/cpod-ai/cpod-go
Source: github.com/cpod-ai/cpod-sdk/tree/main/sdks/go
Go: ≥ 1.21


Installation

go get github.com/cpod-ai/cpod-go@latest

Client Initialization

package main
 
import (
    "context"
    "os"
    "time"
 
    "github.com/cpod-ai/cpod-go"
)
 
func main() {
    // Reads CPOD_API_KEY from environment
    client := cpod.NewClient()
 
    // With options
    client := cpod.NewClient(
        cpod.WithAPIKey(os.Getenv("CPOD_API_KEY")),
        cpod.WithBaseURL("https://api.cyberpod.app/v1"),
        cpod.WithTimeout(30 * time.Second),
        cpod.WithMaxRetries(3),
        cpod.WithHTTPClient(customHTTPClient),
    )
 
    ctx := context.Background()
    _ = ctx // pass ctx to all service methods
}

The Client struct is safe for concurrent use. Create one instance and share it across goroutines.


PodServiceclient.Pods

List pods

result, err := client.Pods.List(ctx, &cpod.PodListParams{
    TenantID: "acme-corp",
    Status:   cpod.PodStatusRunning,
    Region:   cpod.String("us-east-1"),
    Limit:    cpod.Int(50),
})
if err != nil {
    return err
}
for _, pod := range result.Data {
    fmt.Printf("%s: %s [%s]\n", pod.ID, pod.Name, pod.Status)
}
// result.NextCursor — pass to next call for pagination

Get a pod

pod, err := client.Pods.Get(ctx, "pod_01jm8xk2y3z")

Create a pod

pod, err := client.Pods.Create(ctx, &cpod.PodCreateParams{
    TenantID:  "acme-corp",
    Name:      "my-worker",
    Image:     "cpod/worker:latest",
    CPU:       2.0,
    MemoryMB:  4096,
    Region:    "us-east-1",
    Env:       map[string]string{"NODE_ENV": "production"},
    Labels:    map[string]string{"team": "platform"},
})

Update a pod

pod, err := client.Pods.Update(ctx, "pod_01jm8xk2y3z", &cpod.PodUpdateParams{
    Name:   cpod.String("renamed-worker"),
    Labels: map[string]string{"app": "worker-v2"},
})

Delete a pod

err := client.Pods.Delete(ctx, "pod_01jm8xk2y3z")

Lifecycle operations

err = client.Pods.Start(ctx, "pod_01jm8xk2y3z")
err = client.Pods.Stop(ctx, "pod_01jm8xk2y3z", &cpod.PodStopParams{
    GracePeriodSeconds: cpod.Int(30),
})
err = client.Pods.Restart(ctx, "pod_01jm8xk2y3z")

Stream logs

stream, err := client.Pods.Logs(ctx, "pod_01jm8xk2y3z", &cpod.PodLogsParams{
    Follow: true,
    Tail:   100,
})
if err != nil {
    return err
}
defer stream.Close()
 
scanner := bufio.NewScanner(stream)
for scanner.Scan() {
    fmt.Println(scanner.Text())
}

Auto-paginated iterator

iter := client.Pods.ListAll(ctx, &cpod.PodListParams{TenantID: "acme-corp"})
for iter.Next() {
    pod := iter.Current()
    fmt.Println(pod.ID)
}
if err := iter.Err(); err != nil {
    return err
}

TenantServiceclient.Tenants

// List
result, err := client.Tenants.List(ctx, &cpod.TenantListParams{Limit: cpod.Int(50)})
 
// Get
tenant, err := client.Tenants.Get(ctx, "acme-corp")
 
// Create
tenant, err := client.Tenants.Create(ctx, &cpod.TenantCreateParams{
    ID:     "acme-corp",
    Name:   "Acme Corporation",
    Plan:   cpod.PlanEnterprise,
    Region: "us-east-1",
    Metadata: map[string]string{"salesforce_id": "SF-001234"},
})
 
// Update
tenant, err := client.Tenants.Update(ctx, "acme-corp", &cpod.TenantUpdateParams{
    Name: cpod.String("Acme Corp (Updated)"),
})
 
// Members
err = client.Tenants.AddMember(ctx, "acme-corp", &cpod.AddMemberParams{
    UserID: "user_123",
    Role:   cpod.RoleAdmin,
})
err = client.Tenants.RemoveMember(ctx, "acme-corp", "user_123")
 
// Policy
err = client.Tenants.SetPolicy(ctx, "acme-corp", &cpod.TenantPolicy{
    MaxPods:        100,
    AllowedRegions: []string{"us-east-1", "eu-west-1"},
    RequireLabels:  []string{"team", "env"},
    IPAllowlist:    []string{"10.0.0.0/8"},
})

EventServiceclient.Events

Query events

result, err := client.Events.List(ctx, &cpod.EventListParams{
    TenantID: "acme-corp",
    Type:     cpod.String("pod.started"),
    Since:    cpod.Time(time.Now().Add(-24 * time.Hour)),
    Limit:    cpod.Int(100),
})

SSE subscription

sub, err := client.Events.Subscribe(ctx, &cpod.EventSubscribeParams{
    TenantID: "acme-corp",
    Types:    []string{"pod.started", "pod.stopped", "pod.error"},
})
if err != nil {
    return err
}
defer sub.Close()
 
for {
    select {
    case event, ok := <-sub.Events():
        if !ok {
            return nil // stream closed
        }
        fmt.Printf("[%s] %s on %s\n", event.Timestamp, event.Type, event.ResourceID)
    case err := <-sub.Errors():
        log.Printf("SSE error: %v", err)
    case <-ctx.Done():
        return ctx.Err()
    }
}

WebSocket subscription

ws, err := client.Events.SubscribeWebSocket(ctx, &cpod.EventSubscribeParams{
    TenantID: "acme-corp",
    Types:    []string{"pod.*"},
})
if err != nil {
    return err
}
defer ws.Close()
 
for event := range ws.Events() {
    fmt.Println(event.Type, event.ResourceID)
}

Types

type Pod struct {
    ID        string            `json:"id"`
    TenantID  string            `json:"tenantId"`
    Name      string            `json:"name"`
    Status    PodStatus         `json:"status"`
    Image     string            `json:"image"`
    CPU       float64           `json:"cpu"`
    MemoryMB  int               `json:"memoryMb"`
    Region    string            `json:"region"`
    Env       map[string]string `json:"env"`
    Labels    map[string]string `json:"labels"`
    CreatedAt time.Time         `json:"createdAt"`
    UpdatedAt time.Time         `json:"updatedAt"`
    StartedAt *time.Time        `json:"startedAt,omitempty"`
    StoppedAt *time.Time        `json:"stoppedAt,omitempty"`
}
 
type PodStatus string
 
const (
    PodStatusPending     PodStatus = "pending"
    PodStatusRunning     PodStatus = "running"
    PodStatusStopped     PodStatus = "stopped"
    PodStatusError       PodStatus = "error"
    PodStatusTerminating PodStatus = "terminating"
)

Helper Functions

The SDK provides pointer helpers for optional fields:

cpod.String("value")     // *string
cpod.Int(42)             // *int
cpod.Bool(true)          // *bool
cpod.Float64(1.5)        // *float64
cpod.Time(time.Now())    // *time.Time

Error Handling

import "github.com/cpod-ai/cpod-go/errors"
 
pod, err := client.Pods.Get(ctx, "pod_nonexistent")
if err != nil {
    var notFound *errors.NotFoundError
    var validation *errors.ValidationError
    var auth *errors.AuthError
    var rateLimit *errors.RateLimitError
    var apiErr *errors.APIError
 
    switch {
    case errors.As(err, &notFound):
        fmt.Println("Not found:", notFound.Message)
    case errors.As(err, &validation):
        for field, msg := range validation.Fields {
            fmt.Printf("  %s: %s\n", field, msg)
        }
    case errors.As(err, &auth):
        fmt.Println("Auth error:", auth.Status, auth.Message)
    case errors.As(err, &rateLimit):
        fmt.Printf("Rate limited. Retry after %ds\n", rateLimit.RetryAfter)
    case errors.As(err, &apiErr):
        fmt.Printf("API error %d [%s]: %s\n", apiErr.Status, apiErr.Code, apiErr.Message)
    default:
        return fmt.Errorf("unexpected error: %w", err)
    }
}

All SDK functions accept a context.Context as the first argument. Use it for cancellation, deadlines, and request-scoped values (e.g., trace IDs).