#Getting Started with the Claude API in Go
In this tutorial, we’re going to walk through how to use Anthropic’s Claude API in Go using the official SDK — no Python, no boilerplate frameworks. You’ll learn how to set up the client, send your first message to Claude, and build a proper multi-turn conversation that maintains context across exchanges. These two patterns are the foundation for any AI-powered Go tool you want to build.
If you prefer video, I’ve covered this exact material on YouTube:
Prerequisites
Before we get started, you’ll need:
- Go 1.21 or later
- An Anthropic account with an API key
- Basic familiarity with Go modules and functions
Project Setup
Create a new directory for your project and initialise a Go module:
mkdir claude-quickstart && cd claude-quickstart
go mod init claude-quickstart
Install the official Anthropic Go SDK:
go get github.com/anthropics/anthropic-sdk-go
Next, set your API key as an environment variable. The SDK reads ANTHROPIC_API_KEY automatically, so we never hardcode it:
# macOS / Linux
export ANTHROPIC_API_KEY="your-api-key-here"
# Windows (Command Prompt)
setx ANTHROPIC_API_KEY "your-api-key-here"
Grab your key from console.anthropic.com. Keep it out of source control — if it lands in a public repo, rotate it immediately.
Creating the Client
At the top of main.go, read the API key and create the client:
package main
import (
"log"
"os"
"github.com/anthropics/anthropic-sdk-go"
"github.com/anthropics/anthropic-sdk-go/option"
)
func main() {
apiKey := os.Getenv("ANTHROPIC_API_KEY")
if apiKey == "" {
log.Fatal("ANTHROPIC_API_KEY environment variable is not set")
}
client := anthropic.NewClient(option.WithAPIKey(apiKey))
_ = client
}
anthropic.NewClient takes a variadic list of options. Passing option.WithAPIKey is optional if ANTHROPIC_API_KEY is set in your environment — the SDK picks it up automatically. We’re being explicit here so the error is obvious if the key is missing, rather than getting a confusing 401 later.
One line, and the SDK handles HTTP, retries, and rate-limit back-off for you.
Single-Turn Completion
Let’s send our first message. Add a singleTurn function:
func singleTurn(client anthropic.Client) {
resp, err := client.Messages.New(context.Background(), anthropic.MessageNewParams{
Model: anthropic.ModelClaudeOpus4_7,
MaxTokens: 256,
Messages: []anthropic.MessageParam{
anthropic.NewUserMessage(anthropic.NewTextBlock("What is the Go programming language best known for?")),
},
})
if err != nil {
log.Fatalf("API error: %v", err)
}
for _, block := range resp.Content {
switch b := block.AsAny().(type) {
case anthropic.TextBlock:
fmt.Println(b.Text)
}
}
}
A few things worth pointing out:
Model — anthropic.ModelClaudeOpus4_7 is a typed constant from the SDK. No magic strings, no typo risk. The SDK exposes constants for all available models.
MaxTokens — caps how long the response can be. Tokens map roughly to words. 256 is fine for a short answer; push this to 4,000–8,000 for code generation or documentation.
Messages is a slice — even for a single question, you pass a list. The API is built around conversation history from the ground up, which we’ll use properly in the next section.
NewUserMessage and NewTextBlock are SDK helpers that construct the right structure. Text is the most common content type, but the API also supports images and documents.
Reading the response — resp.Content is a slice of blocks, not just a string. Claude can return text, tool calls, and thinking blocks mixed together. AsAny() with a type switch is how you pattern-match on what came back. For now we only want text.
Multi-Turn Conversation
A single question is useful, but most real tools need back-and-forth — a CLI assistant that refines its output, or a code reviewer that takes your feedback. Add a multiTurn function:
func multiTurn(client anthropic.Client) {
history := []anthropic.MessageParam{}
turns := []string{
"Tell me one reason Go is a good fit for building AI tooling.",
"Can you give me a short code example in Go?",
}
for _, userText := range turns {
fmt.Printf("\nYou: %s\n", userText)
history = append(history, anthropic.NewUserMessage(anthropic.NewTextBlock(userText)))
resp, err := client.Messages.New(context.Background(), anthropic.MessageNewParams{
Model: anthropic.ModelClaudeOpus4_7,
MaxTokens: 512,
Messages: history,
})
if err != nil {
log.Fatalf("API error: %v", err)
}
var assistantText string
for _, block := range resp.Content {
switch b := block.AsAny().(type) {
case anthropic.TextBlock:
assistantText = b.Text
fmt.Printf("Claude: %s\n", b.Text)
}
}
history = append(history, anthropic.NewAssistantMessage(anthropic.NewTextBlock(assistantText)))
}
}
The key idea: history is your entire conversation. Before each API call you append the new user message, send the full slice, then append the assistant’s reply. The model has no persistent memory between calls — you own the state, and you send it back every time.
This sounds like extra work, but it gives you complete control. You can edit history, inject context, summarise old messages, or prepend a system prompt. You’re not locked into whatever session state a framework manages for you.
Production note: history grows with every turn, and the API charges on input tokens — so all that history is billed each call. For long sessions, implement a rolling window (keep the last N turns) or summarise older messages to a shorter form. For getting started, the full-history pattern is exactly right.
Error Handling and Timeouts
The examples above use log.Fatalf which is fine for demos but terminates the process on any error. In production you’d return errors up the call stack and handle them gracefully. Here’s the pattern:
resp, err := client.Messages.New(ctx, anthropic.MessageNewParams{
Model: anthropic.ModelClaudeOpus4_7,
MaxTokens: 512,
Messages: history,
})
if err != nil {
return fmt.Errorf("claude API call failed: %w", err)
}
For long-running calls — or any network call really — wrap your context with a timeout so your application doesn’t hang if the API is slow to respond:
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
resp, err := client.Messages.New(ctx, anthropic.MessageNewParams{
Model: anthropic.ModelClaudeOpus4_7,
MaxTokens: 512,
Messages: history,
})
if err != nil {
if ctx.Err() == context.DeadlineExceeded {
return fmt.Errorf("request timed out after 30s")
}
return fmt.Errorf("claude API call failed: %w", err)
}
context.WithTimeout returns a new context and a cancel function. Always defer cancel() immediately after — this releases resources even if the deadline isn’t hit.
Running the Code
With both functions wired up in main():
func main() {
apiKey := os.Getenv("ANTHROPIC_API_KEY")
if apiKey == "" {
log.Fatal("ANTHROPIC_API_KEY environment variable is not set")
}
client := anthropic.NewClient(option.WithAPIKey(apiKey))
fmt.Println("=== Single-turn completion ===")
singleTurn(client)
fmt.Println("\n=== Multi-turn conversation ===")
multiTurn(client)
}
Run it:
go run main.go
You’ll see the single-turn answer first, then the two-turn exchange where the second reply builds on the first — that context carry-through is the whole point.
The full source is on GitHub: github.com/TutorialEdge/claude-api-go/tree/main/01-getting-started
Frequently Asked Questions
What is the Anthropic Go SDK?
The Anthropic Go SDK (github.com/anthropics/anthropic-sdk-go) is the official Go client library for the Claude API. It handles authentication, HTTP, retries, rate-limit back-off, and provides typed structs for all request and response parameters so you’re not marshalling raw JSON by hand.
How do I set my Claude API key in Go?
Set the ANTHROPIC_API_KEY environment variable before running your program (export ANTHROPIC_API_KEY="sk-..." on macOS/Linux). The SDK reads it automatically. You can also pass it explicitly via option.WithAPIKey(key) when creating the client, which is useful if you’re loading secrets from a vault or config file at runtime.
What is MaxTokens in the Claude API?
MaxTokens caps the length of the model’s response. Tokens are roughly equivalent to words (a token is ~4 characters of English text). Set it low (256–512) for short factual answers, and higher (4,000–8,000) when asking Claude to generate code, write documentation, or produce long-form content. Note that the total tokens billed per call is input tokens + output tokens.
How does multi-turn conversation work with the Claude API?
The Claude API is stateless — it has no memory between calls. You maintain conversation history yourself as a slice of anthropic.MessageParam, appending each user message and assistant reply in turn. On every API call you send the full history slice, giving the model the context it needs to continue the conversation coherently. This gives you full control: you can edit, trim, summarise, or inject messages into history as needed.
Which Claude model should I use?
For most tasks, start with anthropic.ModelClaudeOpus4_7 (Claude Opus 4.7) — it’s Anthropic’s most capable model. If you need faster responses or lower cost at higher volume, anthropic.ModelClaudeSonnet4_5 offers a strong capability-to-cost ratio. Check Anthropic’s model overview for the current lineup and recommended use cases.
Does the Anthropic Go SDK support streaming?
Yes. The SDK supports streaming responses so your application can display output as it’s generated rather than waiting for the full response. Streaming is covered in a follow-up tutorial in this series.
What’s Next
You now have the two foundational patterns for building with Claude in Go: single-turn completions for quick tasks, and stateful multi-turn conversations for anything that needs context. These compose into almost any AI-powered tool you’d want to build.
The natural next steps in this series:
- Streaming responses — display Claude’s output token-by-token as it arrives, rather than waiting for the full reply
- Tool use — let Claude call functions in your Go code to take actions, look up data, or run calculations
- Managing long conversations — strategies for summarising history and keeping token costs under control as sessions grow
Watch the YouTube video for a live walkthrough of everything in this tutorial. Drop any questions in the comments.
Continue Learning
Building AI Agents in Go
Learn how to build AI agents in Go that can use tools, make decisions, and complete tasks autonomously.
Building AI Applications with LangChainGo
Learn how to build AI-powered applications in Go using the LangChainGo library with practical examples.
Building RAG Applications in Go
Learn how to build Retrieval Augmented Generation (RAG) applications in Go using LangChainGo and Ollama.
Calling Ollama from a Go Application
Learn how to interact with Ollama's REST API from Go to build AI-powered applications.