# Go SDK

> Use PromptRails from Go services with a small client for agents, prompts, executions, traces, and scores.

Source: https://0.0.0.0:3000/go-sdk

The official Go SDK for PromptRails provides a fully typed client for interacting with the PromptRails API from any Go application.

<div style={{ display: 'flex', gap: '0.75rem', marginBottom: '0.5rem' }}>
  <a href="https://github.com/promptrails/go-sdk" target="_blank" rel="noopener noreferrer">
    GitHub
  </a>
  <span style={{ color: 'var(--color-muted-foreground)' }}>·</span>
  <a
    href="https://pkg.go.dev/github.com/promptrails/go-sdk"
    target="_blank"
    rel="noopener noreferrer"
  >
    pkg.go.dev
  </a>
</div>

Use the Go SDK when a Go service needs to execute agents, send traces, inspect runs, or manage workspace resources from backend code. You do not need it for product-side experimentation; use Studio, chat, triggers, or Agent UI deployments first when the workflow can be tested without code.

For production services, keep the API key scoped to the operations the service actually performs and use traces to verify runtime behavior.

## Installation

```bash
go get github.com/promptrails/go-sdk@v0.6.0
```

Requires Go 1.21 or later.

Current release: **v0.6.0** — adds the standalone [`tracing`](#tracing) package
for sending spans to PromptRails from any code. See the
[changelog](https://github.com/promptrails/go-sdk/releases).

<TechnicalDetails title="Client setup and resource reference">

## Client Initialization

```go
import promptrails "github.com/promptrails/go-sdk"

client := promptrails.NewClient("your-api-key")
```

### With Options

```go
import (
    "time"
    promptrails "github.com/promptrails/go-sdk"
)

client := promptrails.NewClient("your-api-key",
    promptrails.WithBaseURL("https://api.promptrails.ai"),  // default
    promptrails.WithTimeout(30 * time.Second),               // default
    promptrails.WithMaxRetries(3),                           // default
)
```

## Configuration

| Option           | Type          | Default                      | Description                   |
| ---------------- | ------------- | ---------------------------- | ----------------------------- |
| `WithBaseURL`    | string        | `https://api.promptrails.ai` | API base URL                  |
| `WithTimeout`    | time.Duration | 30s                          | HTTP request timeout          |
| `WithMaxRetries` | int           | 3                            | Maximum retry attempts on 5xx |

The API key is sent via the `X-API-Key` header with every request.

## Available Resources

| Resource       | Field                  | Description                                                                            |
| -------------- | ---------------------- | -------------------------------------------------------------------------------------- |
| Agents         | `client.Agents`        | Agent CRUD, versioning, execution                                                      |
| Prompts        | `client.Prompts`       | Prompt CRUD, versioning, execution                                                     |
| Executions     | `client.Executions`    | Execution listing and details                                                          |
| Credentials    | `client.Credentials`   | Credential management                                                                  |
| Data Sources   | `client.DataSources`   | Data source CRUD, versioning, execution                                                |
| Chat           | `client.Chat`          | Send messages to chat sessions                                                         |
| Traces         | `client.Traces`        | Trace listing and filtering                                                            |
| Costs          | `client.Costs`         | Cost analysis and summaries                                                            |
| MCP Tools      | `client.MCPTools`      | MCP tool management                                                                    |
| Approvals      | `client.Approvals`     | Approval request management                                                            |
| Scores         | `client.Scores`        | Scoring and evaluation                                                                 |
| A2A            | `client.A2A`           | Agent-to-Agent protocol                                                                |
| Agent Triggers | `client.AgentTriggers` | Agent trigger management (generic webhook, Slack, Telegram, Teams, WhatsApp, schedule) |

</TechnicalDetails>

## Common Operations

### Execute an Agent

```go
ctx := context.Background()

result, err := client.Agents.Execute(ctx, "agent-id", &promptrails.ExecuteAgentParams{
    Input: map[string]any{"message": "Hello, world!"},
    Sync:  true,
})
if err != nil {
    log.Fatal(err)
}

fmt.Println(result.Data.Output)
```

<TechnicalDetails title="More Go SDK operations">

### List Agents

```go
agents, err := client.Agents.List(ctx, &promptrails.ListAgentsParams{
    Page:  1,
    Limit: 20,
})
if err != nil {
    log.Fatal(err)
}

for _, agent := range agents.Data {
    fmt.Printf("%s (%s)\n", agent.Name, agent.Type)
}
```

### Create a Prompt

```go
prompt, err := client.Prompts.Create(ctx, &promptrails.CreatePromptParams{
    Name:        "Summarizer",
    Description: "Summarizes text",
})
if err != nil {
    log.Fatal(err)
}

fmt.Println(prompt.Data.ID)
```

### View Executions

```go
executions, err := client.Executions.List(ctx, &promptrails.ListExecutionsParams{
    Page:  1,
    Limit: 10,
})
if err != nil {
    log.Fatal(err)
}

for _, exec := range executions.Data {
    fmt.Printf("ID: %s, Status: %s\n", exec.ID, exec.Status)
}
```

### Approve an Execution

```go
err := client.Approvals.Decide(ctx, "approval-id", &promptrails.DecideApprovalParams{
    Decision: "approved",
    Reason:   "Looks good",
})
```

### Stream a Chat Turn

`Chat.SendMessageStream` posts a user message and returns a `*ChatStream`
that yields typed events on the same HTTP connection. Cancel by
cancelling `ctx`; always `defer stream.Close()`.

```go
session, err := client.Chat.CreateSession(ctx, &promptrails.CreateSessionParams{
    AgentID: "agent-id",
})
if err != nil {
    log.Fatal(err)
}

stream, err := client.Chat.SendMessageStream(ctx, session.ID, &promptrails.SendMessageParams{
    Content: "What is PromptRails?",
})
if err != nil {
    log.Fatal(err)
}
defer stream.Close()

for stream.Next() {
    switch e := stream.Event().(type) {
    case *promptrails.ExecutionEvent:
        log.Printf("execution_id: %s", e.ExecutionID)
    case *promptrails.ThinkingEvent:
        log.Printf("[thinking] %s", e.Content)
    case *promptrails.ToolStartEvent:
        log.Printf("[tool_start] %s", e.Name)
    case *promptrails.ToolEndEvent:
        log.Printf("[tool_end] %s (%s)", e.Name, e.Summary)
    case *promptrails.ContentEvent:
        fmt.Print(e.Content)
    case *promptrails.DoneEvent:
        fmt.Printf("\n[done] %d tokens\n", e.TokenUsage.TotalTokens)
    case *promptrails.ErrorEvent:
        log.Fatalf("[error] %s", e.Message)
    }
}
if err := stream.Err(); err != nil {
    log.Fatal(err)
}
```

### Stream an Existing Execution

When an execution was started outside a chat (e.g. `Agents.Execute`),
subscribe to its live event stream:

```go
stream, err := client.Executions.Stream(ctx, executionID)
if err != nil {
    log.Fatal(err)
}
defer stream.Close()

for stream.Next() {
    if e, ok := stream.Event().(*promptrails.ContentEvent); ok {
        fmt.Print(e.Content)
    }
}
```

</TechnicalDetails>

<TechnicalDetails title="Go SDK advanced details">

## Typed Agent Config

`Agents.CreateVersion` takes a typed `AgentConfig` — an interface
implemented by the five concrete variants. Each concrete type's
`MarshalJSON` injects the required `type` discriminator.

```go
import promptrails "github.com/promptrails/go-sdk"

// Simple agent — one prompt per execution
simple := promptrails.SimpleAgentConfig{
    PromptID: "prompt-id",
}

// Chain agent — prompts run sequentially
chain := promptrails.ChainAgentConfig{
    PromptIDs: []promptrails.PromptLink{
        {PromptID: "p1", Role: "step1", SortOrder: 0},
        {PromptID: "p2", Role: "step2", SortOrder: 1},
    },
}

_, err := client.Agents.CreateVersion(ctx, "agent-id", &promptrails.CreateVersionParams{
    Version:    "1.0.0",
    Config:     simple, // or chain, MultiAgentConfig, WorkflowAgentConfig, CompositeAgentConfig
    SetCurrent: true,
})
```

See [Agent Versioning](/docs/agent-versioning) for the per-type field
reference.

## Tracing

The `github.com/promptrails/go-sdk/tracing` package sends spans to PromptRails from any code, without managing your prompts or agents on the platform. It depends only on the standard library and needs an API key with the `traces:write` scope.

```go
import "github.com/promptrails/go-sdk/tracing"

tracer := tracing.NewTracer("pr_...")
defer tracer.Shutdown()

_ = tracer.Span(ctx, "agent-run", tracing.KindAgent, func(ctx context.Context, root *tracing.Span) error {
    root.SetInput(map[string]any{"q": "weather?"})
    return tracer.Span(ctx, "llm-call", tracing.KindLLM, func(ctx context.Context, llm *tracing.Span) error {
        // SetUsage(promptTokens, completionTokens, totalTokens); pass -1 for an
        // unknown count — total is computed from prompt+completion when it is -1.
        llm.SetModel("gpt-4o").SetUsage(120, 30, -1)
        return nil
    })
})
```

Spans created from a child context automatically share the trace and link to their parent. OpenTelemetry users can point a standard OTLP/HTTP exporter at the PromptRails OTLP endpoint instead — see the [Tracing](/docs/tracing) guide.

## SDK Version

```go
import promptrails "github.com/promptrails/go-sdk"

fmt.Println(promptrails.Version) // "0.6.0"
```

Every request is sent with `User-Agent: promptrails-go/<version>` so
backend telemetry can attribute traffic to the SDK release.

## Error Handling

The SDK returns typed errors for different HTTP status codes. Use `errors.As` to handle specific error types:

```go
import "errors"

result, err := client.Agents.Execute(ctx, "invalid-id", &promptrails.ExecuteAgentParams{
    Input: map[string]any{},
})
if err != nil {
    var notFound *promptrails.NotFoundError
    var validation *promptrails.ValidationError
    var unauthorized *promptrails.UnauthorizedError
    var forbidden *promptrails.ForbiddenError
    var rateLimit *promptrails.RateLimitError
    var serverErr *promptrails.ServerError

    switch {
    case errors.As(err, &notFound):
        fmt.Printf("Agent not found: %s\n", notFound.Message)
    case errors.As(err, &validation):
        fmt.Printf("Invalid input: %s\n", validation.Message)
    case errors.As(err, &unauthorized):
        fmt.Printf("Invalid API key: %s\n", unauthorized.Message)
    case errors.As(err, &forbidden):
        fmt.Printf("Insufficient permissions: %s\n", forbidden.Message)
    case errors.As(err, &rateLimit):
        fmt.Printf("Rate limited: %s\n", rateLimit.Message)
    case errors.As(err, &serverErr):
        fmt.Printf("Server error: %s\n", serverErr.Message)
    default:
        fmt.Printf("Unexpected error: %v\n", err)
    }
}
```

### Error Types

| Error                | HTTP Status | Description                                       |
| -------------------- | ----------- | ------------------------------------------------- |
| `ValidationError`    | 400         | Invalid request parameters                        |
| `UnauthorizedError`  | 401         | Invalid or missing API key                        |
| `QuotaExceededError` | 402         | Plan quota exceeded                               |
| `ForbiddenError`     | 403         | Insufficient permissions or IP/origin restriction |
| `NotFoundError`      | 404         | Resource not found                                |
| `RateLimitError`     | 429         | Rate limit exceeded                               |
| `ServerError`        | 5xx         | Server-side error                                 |
| `APIError`           | Any         | Base type for all API errors                      |

All error types embed `APIError` which includes:

- `StatusCode` -- HTTP status code
- `Message` -- Human-readable error message
- `Code` -- Optional error code string
- `Details` -- Optional map with additional error details

## Context Support

All SDK methods require a `context.Context` as the first argument, enabling cancellation and timeouts:

```go
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()

result, err := client.Agents.Execute(ctx, "agent-id", &promptrails.ExecuteAgentParams{
    Input: map[string]any{"message": "Hello"},
    Sync:  true,
})
```

## Pagination

List endpoints return paginated responses:

```go
// Page-based pagination
page1, _ := client.Agents.List(ctx, &promptrails.ListAgentsParams{Page: 1, Limit: 20})
page2, _ := client.Agents.List(ctx, &promptrails.ListAgentsParams{Page: 2, Limit: 20})

fmt.Printf("Total: %d, Pages: %d\n", page1.Meta.Total, page1.Meta.TotalPages)
```

</TechnicalDetails>

## Related Topics

- [Examples](https://github.com/promptrails/examples/tree/main/go) -- Ready-to-run code examples
- [Quickstart](/docs/quickstart) -- Getting started guide
- [Python SDK](/docs/python-sdk) -- Python alternative
- [JavaScript SDK](/docs/javascript-sdk) -- JavaScript/TypeScript alternative
- [CLI](/docs/cli) -- Command-line interface
- [API Keys and Scopes](/docs/api-keys-and-scopes) -- API key management
- [REST API Reference](/docs/rest-api-reference) -- Underlying REST API
