Skip to main content

Go Integration

Also available in: Python · PHP · Node.js

The "gateway base URL" is the address of your Observra Gateway (https://gateway.observra.in) - your app sends requests here instead of directly to OpenAI, Anthropic, or whichever provider you use. The "gateway key" is a per-Application credential you generate in the Observra Dashboard; it authenticates your app to the gateway and is separate from your provider's own API key, which you still keep and send yourself. See Quickstart and Gateway Authentication if you haven't set these up yet.

Try it now

Paste in a gateway URL, your gateway key, and a provider key to send a real request straight from this page - no code required yet.

Loading playground...

Environment variables

GATEWAY_URL
GATEWAY_KEY obs_...
OPENAI_API_KEY / ANTHROPIC_API_KEY / GEMINI_API_KEY / GROQ_API_KEY / OPENROUTER_API_KEY / OLLAMA_API_KEY

Install:

go get github.com/sashabaranov/go-openai
go get github.com/tmc/langchaingo
go get github.com/cloudwego/eino-ext/components/model/openai
go get github.com/cloudwego/eino-ext/components/model/claude
go get google.golang.org/genai

Header injector

Every native SDK example below reuses this small helper to attach X-Provider-Key (and, optionally, traceparent) to outgoing requests, since most Go SDKs let you supply a custom *http.Client:

package gatewayclient

import (
"net/http"
"strings"
)

func BaseURL(gatewayURL, route string) string {
return strings.TrimRight(gatewayURL, "/") + "/" + strings.TrimLeft(route, "/")
}

type headerInjector struct {
headers map[string]string
base http.RoundTripper
}

func (t *headerInjector) RoundTrip(req *http.Request) (*http.Response, error) {
clone := req.Clone(req.Context())
for k, v := range t.headers {
clone.Header.Set(k, v)
}
return t.base.RoundTrip(clone)
}

func HTTPClient(extraHeaders map[string]string) *http.Client {
return &http.Client{Transport: &headerInjector{headers: extraHeaders, base: http.DefaultTransport}}
}

Optional: distributed tracing

To send a real traceparent header (see Trace Context), install OpenTelemetry:

go get go.opentelemetry.io/otel go.opentelemetry.io/otel/sdk go.opentelemetry.io/otel/trace
package tracing

import (
"context"
"fmt"

"go.opentelemetry.io/otel"
sdktrace "go.opentelemetry.io/otel/sdk/trace"
"go.opentelemetry.io/otel/trace"
)

func NewProvider() *sdktrace.TracerProvider {
tp := sdktrace.NewTracerProvider()
otel.SetTracerProvider(tp)
return tp
}

// Starts a real span and returns the traceparent header derived from it,
// the child context to run the gateway call in, and the span to end after.
func StartTraceparent(ctx context.Context, name string) (context.Context, trace.Span, string) {
tracer := otel.Tracer("my-service")
ctx, span := tracer.Start(ctx, name)
sc := span.SpanContext()
traceparent := fmt.Sprintf("00-%s-%s-01", sc.TraceID().String(), sc.SpanID().String())
return ctx, span, traceparent
}

Raw HTTP request

package main

import (
"bytes"
"encoding/json"
"net/http"
"os"
)

func main() {
body, _ := json.Marshal(map[string]any{
"model": "gpt-4o-mini",
"messages": []map[string]string{{"role": "user", "content": "hello"}},
})

req, _ := http.NewRequest("POST", os.Getenv("GATEWAY_URL")+"/openai/chat/completions", bytes.NewReader(body))
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Authorization", "Bearer "+os.Getenv("GATEWAY_KEY"))
req.Header.Set("X-Provider-Key", os.Getenv("OPENAI_API_KEY"))

res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()

var out map[string]any
json.NewDecoder(res.Body).Decode(&out)
}
curl -X POST "${GATEWAY_URL}/openai/chat/completions" \
-H "Authorization: Bearer ${GATEWAY_KEY}" \
-H "X-Provider-Key: ${OPENAI_API_KEY}" \
-H "Content-Type: application/json" \
-d '{"model":"gpt-4o-mini","messages":[{"role":"user","content":"hello"}]}'

Native SDKs

Uses sashabaranov/go-openai.

import openai "github.com/sashabaranov/go-openai"

config := openai.DefaultConfig(os.Getenv("GATEWAY_KEY"))
config.BaseURL = gatewayclient.BaseURL(os.Getenv("GATEWAY_URL"), "openai")
config.HTTPClient = gatewayclient.HTTPClient(map[string]string{
"X-Provider-Key": os.Getenv("OPENAI_API_KEY"),
})

client := openai.NewClientWithConfig(config)
resp, err := client.CreateChatCompletion(context.Background(), openai.ChatCompletionRequest{
Model: "gpt-4o-mini",
Messages: []openai.ChatCompletionMessage{{Role: "user", Content: "hello"}},
})

Tool calling (native SDK)

import (
"context"
"encoding/json"

openai "github.com/sashabaranov/go-openai"
)

config := openai.DefaultConfig(os.Getenv("GATEWAY_KEY"))
config.BaseURL = gatewayclient.BaseURL(os.Getenv("GATEWAY_URL"), "openai")
config.HTTPClient = gatewayclient.HTTPClient(map[string]string{
"X-Provider-Key": os.Getenv("OPENAI_API_KEY"),
})
client := openai.NewClientWithConfig(config)

tools := []openai.Tool{{
Type: openai.ToolTypeFunction,
Function: &openai.FunctionDefinition{
Name: "get_weather",
Description: "Get the current weather for a given city.",
Parameters: map[string]any{
"type": "object",
"properties": map[string]any{"location": map[string]any{"type": "string"}},
"required": []string{"location"},
},
},
}}

messages := []openai.ChatCompletionMessage{{Role: "user", Content: "What's the weather in New York?"}}
resp, err := client.CreateChatCompletion(context.Background(), openai.ChatCompletionRequest{
Model: "gpt-4o-mini", Messages: messages, Tools: tools,
})

if calls := resp.Choices[0].Message.ToolCalls; len(calls) > 0 {
var args struct{ Location string `json:"location"` }
json.Unmarshal([]byte(calls[0].Function.Arguments), &args)
result := "It's 31C and partly cloudy in " + args.Location + "."

messages = append(messages, resp.Choices[0].Message, openai.ChatCompletionMessage{
Role: "tool", ToolCallID: calls[0].ID, Content: result,
})
followUp, err := client.CreateChatCompletion(context.Background(), openai.ChatCompletionRequest{
Model: "gpt-4o-mini", Messages: messages,
})
fmt.Println(followUp.Choices[0].Message.Content)
}

Wrap context.Background() with tracing.StartTraceparent(...) and add "traceparent": traceparent to gatewayclient.HTTPClient(...) the same way as the other "With trace" tabs if you want this correlated with a trace.

Agent frameworks & SDKs

More advanced: these frameworks wrap the SDKs above behind their own client abstraction. Each still needs the gateway route and X-Provider-Key set on its underlying HTTP client.

import "github.com/tmc/langchaingo/llms/openai"

llm, _ := openai.New(
openai.WithBaseURL(gatewayclient.BaseURL(gatewayURL, "openai")),
openai.WithToken(gatewayKey),
openai.WithModel("gpt-4o-mini"),
openai.WithHTTPClient(gatewayclient.HTTPClient(map[string]string{
"X-Provider-Key": openaiKey,
})),
)

completion, err := llm.GenerateContent(context.Background(), []llms.MessageContent{
llms.TextParts(llms.ChatMessageTypeHuman, "hello"),
})

Every framework tab above adds tracing the same way: call tracing.StartTraceparent(ctx, "agent_run") first, add "traceparent": traceparent to the gatewayclient.HTTPClient(...) headers map, use the returned ctx for the call, and defer span.End().

Next steps