> For the complete documentation index, see [llms.txt](https://docs.nexos.ai/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.nexos.ai/gateway-api/code-examples/go-sdk.md).

# Go SDK

### Setup <a href="#setup" id="setup"></a>

For Open AI compatible:

```bash
go get github.com/openai/openai-go/v3
go get github.com/joho/godotenv
```

For Anthropic compatible:

```go
"github.com/anthropics/anthropic-sdk-go"
"github.com/anthropics/anthropic-sdk-go/option"
"github.com/joho/godotenv"
```

All examples read the API key from a `.env` file. OpenAI SDK clients use the base URL `https://api.nexos.ai/v1`; the Anthropic SDK appends `/v1/messages` itself, so it takes the bare `https://api.nexos.ai`.

```
API_KEY=YOUR_NEXOS_API_KEY
```

Model IDs on nexos.ai are the model names shown in the console (e.g. `GPT 5.6 Sol`, `Claude Sonnet 5`, `Whisper`). List them with `GET /v1/models`.

### Chat Completion

Send a conversation and get the model's next reply — the standard OpenAI-compatible endpoint, supported by most chat models on the platform.

```go
package main

import (
	"context"
	"fmt"
	"os"

	"github.com/joho/godotenv"
	"github.com/openai/openai-go/v3"
	"github.com/openai/openai-go/v3/option"
)

func main() {
	err := godotenv.Load()
	if err != nil {
		panic(err)
	}
	apiKey := os.Getenv("API_KEY")
	client := openai.NewClient(
		option.WithBaseURL("https://api.nexos.ai/v1"),
		option.WithAPIKey(apiKey),
	)
	response, err := client.Chat.Completions.New(context.Background(), openai.ChatCompletionNewParams{
		Model: "GPT 5.6 Sol",
		Messages: []openai.ChatCompletionMessageParamUnion{
			openai.UserMessage("how many letters 'r' in the word 'strawberry'"),
		},
	})
	if err != nil {
		panic(err)
	}
	fmt.Println(response.Choices[0].Message.Content)
}
```

### Messages

The `/v1/messages` endpoint implements the Anthropic Messages API and works with the official Anthropic SDK (`go get github.com/anthropics/anthropic-sdk-go`). It is available for models that list the `messages` endpoint in `GET /v1/models` (e.g. Claude models).

```go
package main

import (
	"context"
	"fmt"
	"os"

	"github.com/anthropics/anthropic-sdk-go"
	"github.com/anthropics/anthropic-sdk-go/option"
	"github.com/joho/godotenv"
)

func main() {
	err := godotenv.Load()
	if err != nil {
		panic(err)
	}
	apiKey := os.Getenv("API_KEY")
	// The Anthropic SDK appends /v1/messages itself, so the base URL must not include /v1
	client := anthropic.NewClient(
		option.WithBaseURL("https://api.nexos.ai"),
		option.WithAPIKey(apiKey),
	)
	response, err := client.Messages.New(context.Background(), anthropic.MessageNewParams{
		Model:     "Claude Sonnet 5",
		MaxTokens: 1024,
		Messages: []anthropic.MessageParam{
			anthropic.NewUserMessage(anthropic.NewTextBlock("how many letters 'r' in the word 'strawberry'")),
		},
	})
	if err != nil {
		panic(err)
	}
	// Claude Sonnet 5 responses may start with a thinking block, so pick the text block explicitly
	for _, block := range response.Content {
		if block.Type == "text" {
			fmt.Println(block.Text)
		}
	}
}
```

### Messages - prompt caching

Reuse a large, stable prompt prefix across calls to cut cost (cached tokens are \~10× cheaper) and latency. `/v1/messages` forwards `cache_control` byte-for-byte, so Anthropic prompt caching works natively. The cached prefix must exceed the model's minimum cacheable length (\~1024 tokens):

```go
package main

import (
	"context"
	"fmt"
	"os"
	"strings"

	"github.com/anthropics/anthropic-sdk-go"
	"github.com/anthropics/anthropic-sdk-go/option"
	"github.com/joho/godotenv"
)

func main() {
	err := godotenv.Load()
	if err != nil {
		panic(err)
	}
	apiKey := os.Getenv("API_KEY")
	// The Anthropic SDK appends /v1/messages itself, so the base URL must not include /v1
	client := anthropic.NewClient(
		option.WithBaseURL("https://api.nexos.ai"),
		option.WithAPIKey(apiKey),
	)
	ctx := context.Background()

	// The cached prefix must exceed the model's minimum cacheable length (~1024 tokens)
	longSystemPrompt := strings.Repeat(
		"You are a meticulous linguist who counts letters in words. "+
			"Always double-check your counts by spelling the word out letter by letter. ", 60)

	ask := func() {
		response, err := client.Messages.New(ctx, anthropic.MessageNewParams{
			Model:     "Claude Sonnet 5",
			MaxTokens: 1024,
			System: []anthropic.TextBlockParam{
				{
					Text:         longSystemPrompt,
					CacheControl: anthropic.NewCacheControlEphemeralParam(),
				},
			},
			Messages: []anthropic.MessageParam{
				anthropic.NewUserMessage(anthropic.NewTextBlock("how many letters 'r' in the word 'strawberry'")),
			},
		})
		if err != nil {
			panic(err)
		}
		fmt.Printf("cache_creation_input_tokens=%d cache_read_input_tokens=%d\n",
			response.Usage.CacheCreationInputTokens, response.Usage.CacheReadInputTokens)
	}

	ask() // first call writes the cache
	ask() // second call reads it back at a reduced rate
}
```

### Messages streaming

Receive the reply incrementally as server-sent events instead of waiting for the whole message — useful for chat UIs and long outputs.

```go
package main

import (
	"context"
	"fmt"
	"os"

	"github.com/anthropics/anthropic-sdk-go"
	"github.com/anthropics/anthropic-sdk-go/option"
	"github.com/joho/godotenv"
)

func main() {
	err := godotenv.Load()
	if err != nil {
		panic(err)
	}
	apiKey := os.Getenv("API_KEY")
	// The Anthropic SDK appends /v1/messages itself, so the base URL must not include /v1
	client := anthropic.NewClient(
		option.WithBaseURL("https://api.nexos.ai"),
		option.WithAPIKey(apiKey),
	)
	stream := client.Messages.NewStreaming(context.Background(), anthropic.MessageNewParams{
		Model:     "Claude Sonnet 5",
		MaxTokens: 1024,
		Messages: []anthropic.MessageParam{
			anthropic.NewUserMessage(anthropic.NewTextBlock("how many letters 'r' in the word 'strawberry'")),
		},
	})
	for stream.Next() {
		event := stream.Current()
		switch eventVariant := event.AsAny().(type) {
		case anthropic.ContentBlockDeltaEvent:
			switch deltaVariant := eventVariant.Delta.AsAny().(type) {
			case anthropic.TextDelta:
				fmt.Print(deltaVariant.Text)
			}
		}
	}
	if stream.Err() != nil {
		panic(stream.Err())
	}
	fmt.Println()
}
```

### Messages with thinking

Let the model reason internally before answering — the response starts with a `thinking` block followed by the final text.

```go
package main

import (
	"context"
	"fmt"
	"os"

	"github.com/anthropics/anthropic-sdk-go"
	"github.com/anthropics/anthropic-sdk-go/option"
	"github.com/joho/godotenv"
)

func main() {
	err := godotenv.Load()
	if err != nil {
		panic(err)
	}
	apiKey := os.Getenv("API_KEY")
	// The Anthropic SDK appends /v1/messages itself, so the base URL must not include /v1
	client := anthropic.NewClient(
		option.WithBaseURL("https://api.nexos.ai"),
		option.WithAPIKey(apiKey),
	)

	// Claude 5 models use adaptive thinking with an effort level
	// (older models use ThinkingConfigParamOfEnabled(budgetTokens) instead)
	response, err := client.Messages.New(context.Background(), anthropic.MessageNewParams{
		Model:     "Claude Sonnet 5",
		MaxTokens: 4096,
		Thinking: anthropic.ThinkingConfigParamUnion{
			OfAdaptive: &anthropic.ThinkingConfigAdaptiveParam{},
		},
		OutputConfig: anthropic.OutputConfigParam{
			Effort: anthropic.OutputConfigEffortMedium,
		},
		Messages: []anthropic.MessageParam{
			anthropic.NewUserMessage(anthropic.NewTextBlock("how many letters 'r' in the word 'strawberry'")),
		},
	})
	if err != nil {
		panic(err)
	}
	for _, block := range response.Content {
		switch variant := block.AsAny().(type) {
		case anthropic.ThinkingBlock:
			thinking := variant.Thinking
			if len(thinking) > 120 {
				thinking = thinking[:120]
			}
			fmt.Printf("[thinking] %s...\n", thinking)
		case anthropic.TextBlock:
			fmt.Println(variant.Text)
		}
	}
}
```

### Messages with tool calls

Let the model call functions you define: it responds with a `tool_use` block, your code runs the tool and sends the result back, and the model produces the final answer.

```go
package main

import (
	"context"
	"encoding/json"
	"fmt"
	"os"
	"strconv"
	"strings"

	"github.com/anthropics/anthropic-sdk-go"
	"github.com/anthropics/anthropic-sdk-go/option"
	"github.com/joho/godotenv"
)

func main() {
	err := godotenv.Load()
	if err != nil {
		panic(err)
	}
	apiKey := os.Getenv("API_KEY")
	// The Anthropic SDK appends /v1/messages itself, so the base URL must not include /v1
	client := anthropic.NewClient(
		option.WithBaseURL("https://api.nexos.ai"),
		option.WithAPIKey(apiKey),
	)
	ctx := context.Background()

	tools := []anthropic.ToolUnionParam{
		{
			OfTool: &anthropic.ToolParam{
				Name:        "count_letters",
				Description: anthropic.String("Count occurrences of a letter in a word"),
				InputSchema: anthropic.ToolInputSchemaParam{
					Properties: map[string]any{
						"word":   map[string]any{"type": "string"},
						"letter": map[string]any{"type": "string"},
					},
					Required: []string{"word", "letter"},
				},
			},
		},
	}
	messages := []anthropic.MessageParam{
		anthropic.NewUserMessage(anthropic.NewTextBlock("Use the count_letters tool to count letters 'r' in the word 'strawberry'")),
	}

	response, err := client.Messages.New(ctx, anthropic.MessageNewParams{
		Model:     "Claude Sonnet 5",
		MaxTokens: 1024,
		Tools:     tools,
		Messages:  messages,
	})
	if err != nil {
		panic(err)
	}

	var toolUse anthropic.ToolUseBlock
	for _, block := range response.Content {
		if variant, ok := block.AsAny().(anthropic.ToolUseBlock); ok {
			toolUse = variant
		}
	}
	fmt.Printf("tool call: %s(%s)\n", toolUse.Name, string(toolUse.Input))

	var input struct {
		Word   string `json:"word"`
		Letter string `json:"letter"`
	}
	err = json.Unmarshal(toolUse.Input, &input)
	if err != nil {
		panic(err)
	}
	result := strconv.Itoa(strings.Count(input.Word, input.Letter))

	messages = append(messages, response.ToParam())
	messages = append(messages, anthropic.NewUserMessage(anthropic.NewToolResultBlock(toolUse.ID, result, false)))

	final, err := client.Messages.New(ctx, anthropic.MessageNewParams{
		Model:     "Claude Sonnet 5",
		MaxTokens: 1024,
		Tools:     tools,
		Messages:  messages,
	})
	if err != nil {
		panic(err)
	}
	for _, block := range final.Content {
		if block.Type == "text" {
			fmt.Println(block.Text)
		}
	}
}
```

### Responses

OpenAI's newer generation API: send text or structured input items and get the model output back.&#x20;

```go
package main

import (
	"context"
	"fmt"
	"os"

	"github.com/joho/godotenv"
	"github.com/openai/openai-go/v3"
	"github.com/openai/openai-go/v3/option"
	"github.com/openai/openai-go/v3/responses"
)

func main() {
	err := godotenv.Load()
	if err != nil {
		panic(err)
	}
	apiKey := os.Getenv("API_KEY")
	client := openai.NewClient(
		option.WithBaseURL("https://api.nexos.ai/v1"),
		option.WithAPIKey(apiKey),
	)
	response, err := client.Responses.New(context.Background(), responses.ResponseNewParams{
		Model: "GPT 5.6 Sol",
		Input: responses.ResponseNewParamsInputUnion{
			OfString: openai.String("how many letters 'r' in the word 'strawberry'"),
		},
	})
	if err != nil {
		panic(err)
	}
	fmt.Println(response.OutputText())
}
```

### Responses - compact conversation

Compress a long stored conversation into a smaller context so it can keep going without hitting the model's context limit. Pass the last response's ID via\
`previous_response_id` — the API returns a new, compacted response whose ID you use to continue the conversation.

```go
package main

import (
	"context"
	"fmt"
	"os"

	"github.com/joho/godotenv"
	"github.com/openai/openai-go/v3"
	"github.com/openai/openai-go/v3/option"
	"github.com/openai/openai-go/v3/responses"
)

func main() {
	err := godotenv.Load()
	if err != nil {
		panic(err)
	}
	apiKey := os.Getenv("API_KEY")
	client := openai.NewClient(
		option.WithBaseURL("https://api.nexos.ai/v1"),
		option.WithAPIKey(apiKey),
	)
	ctx := context.Background()

	// Compacting summarizes a stored conversation so it can continue with a smaller context
	response, err := client.Responses.New(ctx, responses.ResponseNewParams{
		Model: "GPT 5.6 Sol",
		Input: responses.ResponseNewParamsInputUnion{
			OfString: openai.String("how many letters 'r' in the word 'strawberry'"),
		},
		Store: openai.Bool(true),
	})
	if err != nil {
		panic(err)
	}
	fmt.Printf("created: %s\n", response.ID)

	compacted, err := client.Responses.Compact(ctx, responses.ResponseCompactParams{
		Model:              "GPT 5.6 Sol",
		PreviousResponseID: openai.String(response.ID),
		Input:              responses.ResponseCompactParamsInputUnion{OfResponseInputItemArray: []responses.ResponseInputItemUnionParam{}},
	})
	if err != nil {
		panic(err)
	}
	fmt.Printf("compacted: %s\n", compacted.ID)
}
```

### Responses lifecycle

Stored responses (store=true) live on the platform after creation, so you can work with them later: retrieve a response by ID, list the input items it was created from, and delete it when it's no longer needed.

```go
package main

import (
	"context"
	"fmt"
	"os"

	"github.com/joho/godotenv"
	"github.com/openai/openai-go/v3"
	"github.com/openai/openai-go/v3/option"
	"github.com/openai/openai-go/v3/responses"
)

func main() {
	err := godotenv.Load()
	if err != nil {
		panic(err)
	}
	apiKey := os.Getenv("API_KEY")
	client := openai.NewClient(
		option.WithBaseURL("https://api.nexos.ai/v1"),
		option.WithAPIKey(apiKey),
	)
	ctx := context.Background()

	// Create a stored response
	response, err := client.Responses.New(ctx, responses.ResponseNewParams{
		Model: "GPT 5.6 Sol",
		Input: responses.ResponseNewParamsInputUnion{
			OfString: openai.String("how many letters 'r' in the word 'strawberry'"),
		},
		Store: openai.Bool(true),
	})
	if err != nil {
		panic(err)
	}
	fmt.Printf("created: %s\n", response.ID)
	fmt.Printf("output: %s\n", response.OutputText())

	// Get a model response
	retrieved, err := client.Responses.Get(ctx, response.ID, responses.ResponseGetParams{})
	if err != nil {
		panic(err)
	}
	fmt.Printf("retrieved: %s status=%s\n", retrieved.ID, retrieved.Status)

	// List input items
	inputItems, err := client.Responses.InputItems.List(ctx, response.ID, responses.InputItemListParams{})
	if err != nil {
		panic(err)
	}
	for _, item := range inputItems.Data {
		fmt.Printf("input item: %s\n", item.Type)
	}

	// Delete a model response
	err = client.Responses.Delete(ctx, response.ID)
	if err != nil {
		panic(err)
	}
	fmt.Printf("deleted: %s\n", response.ID)
}
```

### Embeddings

Convert text into a numeric vector for semantic search, clustering, and RAG. One vector is returned per input.

```go
package main

import (
	"context"
	"fmt"
	"os"

	"github.com/joho/godotenv"
	"github.com/openai/openai-go/v3"
	"github.com/openai/openai-go/v3/option"
)

func main() {
	err := godotenv.Load()
	if err != nil {
		panic(err)
	}
	apiKey := os.Getenv("API_KEY")
	client := openai.NewClient(
		option.WithBaseURL("https://api.nexos.ai/v1"),
		option.WithAPIKey(apiKey),
	)
	response, err := client.Embeddings.New(context.Background(), openai.EmbeddingNewParams{
		Model: "Text Embedding 3 Large",
		Input: openai.EmbeddingNewParamsInputUnion{
			OfString: openai.String("There are three letters 'r' in the word 'strawberry'."),
		},
	})
	if err != nil {
		panic(err)
	}
	embedding := response.Data[0].Embedding
	fmt.Printf("dimensions: %d\n", len(embedding))
	fmt.Printf("first values: %v\n", embedding[:5])
}
```

### Audio Generation

Convert text to spoken audio (text-to-speech).

```go
package main

import (
	"context"
	"io"
	"os"

	"github.com/joho/godotenv"
	"github.com/openai/openai-go/v3"
	"github.com/openai/openai-go/v3/option"
)

func main() {
	err := godotenv.Load()
	if err != nil {
		panic(err)
	}
	apiKey := os.Getenv("API_KEY")
	client := openai.NewClient(
		option.WithBaseURL("https://api.nexos.ai/v1"),
		option.WithAPIKey(apiKey),
	)
	response, err := client.Audio.Speech.New(context.Background(), openai.AudioSpeechNewParams{
		Model: "tts-1",
		Input: "There are three letters 'r' in the word 'strawberry'.",
		Voice: openai.AudioSpeechNewParamsVoiceUnion{OfString: openai.String("ash")},
	})
	if err != nil {
		panic(err)
	}
	file, err := os.Create("generated.mp3")
	if err != nil {
		panic(err)
	}
	defer file.Close()
	_, err = io.Copy(file, response.Body)
	if err != nil {
		panic(err)
	}
}
```

### Audio Transcription

Transcribe an audio file to text in its original language.

```go
package main

import (
	"context"
	"fmt"
	"os"

	"github.com/joho/godotenv"
	"github.com/openai/openai-go/v3"
	"github.com/openai/openai-go/v3/option"
)

func main() {
	err := godotenv.Load()
	if err != nil {
		panic(err)
	}
	apiKey := os.Getenv("API_KEY")
	client := openai.NewClient(
		option.WithBaseURL("https://api.nexos.ai/v1"),
		option.WithAPIKey(apiKey),
	)
	file, err := os.Open("sound.mp3")
	if err != nil {
		panic(err)
	}
	defer file.Close()
	response, err := client.Audio.Transcriptions.New(context.Background(), openai.AudioTranscriptionNewParams{
		Model: "Whisper",
		File:  file,
	})
	if err != nil {
		panic(err)
	}
	fmt.Println(response.Text)
}
```

### Audio Translation

Transcribe an audio file and translate the text into English.

```go
package main

import (
	"context"
	"fmt"
	"os"

	"github.com/joho/godotenv"
	"github.com/openai/openai-go/v3"
	"github.com/openai/openai-go/v3/option"
)

func main() {
	err := godotenv.Load()
	if err != nil {
		panic(err)
	}
	apiKey := os.Getenv("API_KEY")
	client := openai.NewClient(
		option.WithBaseURL("https://api.nexos.ai/v1"),
		option.WithAPIKey(apiKey),
	)
	file, err := os.Open("sound.mp3")
	if err != nil {
		panic(err)
	}
	defer file.Close()
	response, err := client.Audio.Translations.New(context.Background(), openai.AudioTranslationNewParams{
		Model: "Whisper",
		File:  file,
	})
	if err != nil {
		panic(err)
	}
	fmt.Println(response.Text)
}
```

### Image Generation

Generate an image from a text prompt.

```go
package main

import (
	"context"
	"encoding/base64"
	"fmt"
	"os"

	"github.com/joho/godotenv"
	"github.com/openai/openai-go/v3"
	"github.com/openai/openai-go/v3/option"
)

func main() {
	err := godotenv.Load()
	if err != nil {
		panic(err)
	}
	apiKey := os.Getenv("API_KEY")
	client := openai.NewClient(
		option.WithBaseURL("https://api.nexos.ai/v1"),
		option.WithAPIKey(apiKey),
	)
	response, err := client.Images.Generate(context.Background(), openai.ImageGenerateParams{
		Model:  "GPT Image 2",
		Prompt: "three letters 'r' with strawberry texture",
	})
	if err != nil {
		panic(err)
	}
	image := response.Data[0]
	if image.URL != "" {
		fmt.Println(image.URL)
		return
	}
	data, err := base64.StdEncoding.DecodeString(image.B64JSON)
	if err != nil {
		panic(err)
	}
	err = os.WriteFile("generated.png", data, 0o644)
	if err != nil {
		panic(err)
	}
	fmt.Println("saved to generated.png")
}
```


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.nexos.ai/gateway-api/code-examples/go-sdk.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
