> ## Documentation Index
> Fetch the complete documentation index at: https://sitegpt.ai/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Go SDK

> The official Go client for the SiteGPT API v2: github.com/sitegpt/sitegpt-go.

`sitegpt-go` is the official SiteGPT SDK for Go — a zero-dependency client for
the [SiteGPT API v2](/docs/api-reference/v2/getting-started), mirroring the
[TypeScript](/docs/developers/sdk-typescript) and [Python](/docs/developers/sdk-python)
SDKs.

* **Zero dependencies** — standard library only, built on `net/http`.
* **Structured errors** — every non-2xx response returns a `*sitegpt.Error`
  carrying the API's `code`, `message`, and `hint`.
* **Safe by default** — destructive helpers refuse to run without
  `confirm=true` (locally, before any request), and the bearer token is
  stripped whenever a redirect changes scheme, host, or port.

<Note>
  This SDK drives the platform — creating chatbots, training knowledge, reading
  conversations. To embed the chat widget on your website, use the
  [JavaScript widget SDK](/docs/developers/sdk) instead.
</Note>

## Install

```sh theme={null}
go get github.com/sitegpt/sitegpt-go
```

## Quickstart

Create a scoped API token on the [Agents page](/docs/developers/api-tokens-and-mcp), then:

```go theme={null}
package main

import (
	"context"
	"fmt"
	"os"

	sitegpt "github.com/sitegpt/sitegpt-go"
)

func main() {
	client := sitegpt.NewClient(os.Getenv("SITEGPT_API_TOKEN"))
	ctx := context.Background()

	// List your chatbots and pick one to work with
	chatbots, err := client.Chatbots.List(ctx)
	if err != nil {
		panic(err)
	}
	fmt.Println(chatbots)
	chatbotID := "your-chatbot-id" // an id from the list response

	// Add knowledge to a chatbot
	_, err = client.Knowledge.AddLinks(ctx, chatbotID, sitegpt.JSON{
		"urls": []string{"https://example.com/docs/getting-started"},
	})

	// Send a chat message (starts a new conversation)
	reply, err := client.Messages.Send(ctx, chatbotID, sitegpt.JSON{
		"message": "What are your pricing plans?",
	})
	_ = reply
}
```

Responses decode into `sitegpt.JSON` (a `map[string]any`) carrying the
**whole API envelope** — `ok`, `data`, and `meta` — so payload fields live
under `data`. This differs from the TypeScript and Python SDKs, which
return `data` directly.

## Agent onboarding bootstrap (no token required)

The [agent-first onboarding](/docs/cli/onboarding) bootstrap is a public endpoint —
an AI agent can provision a SiteGPT workspace with no credentials at all. Pass
an empty token and the client sends no `Authorization` header:

```go theme={null}
bootstrap := sitegpt.NewClient("")
started, err := bootstrap.Onboarding.Start(ctx, sitegpt.JSON{
	"websiteUrl": "https://example.com",
})
if err != nil {
	panic(err)
}

// The temporary workspace token lives under the envelope's data:
data := started["data"].(map[string]any)
client := sitegpt.NewClient(data["apiToken"].(string))
```

`Health` is public too; every other endpoint responds 401 until a token is
set.

## Error handling

Every non-2xx response returns a `*sitegpt.Error` carrying the API's error
envelope. Use `errors.As` to inspect it:

```go theme={null}
_, err := client.Chatbots.Get(ctx, "nonexistent-id")

var apiErr *sitegpt.Error
if errors.As(err, &apiErr) {
	fmt.Println(apiErr.Status)  // HTTP status, e.g. 404
	fmt.Println(apiErr.Code)    // machine-readable code, e.g. NOT_FOUND
	fmt.Println(apiErr.Message) // human-readable message
	fmt.Println(apiErr.Hint)    // actionable next step, when the API provides one
	fmt.Println(apiErr.Details) // structured error context (arbitrary JSON), when present
}
```

## Convenience namespaces

The highest-value API groups have first-class methods:

| Namespace              | Methods                                                                                                          |
| ---------------------- | ---------------------------------------------------------------------------------------------------------------- |
| `client.Chatbots`      | `List`, `Get`, `Create`, `Update`, `Delete`, `Dashboard`, `Analytics`                                            |
| `client.Knowledge`     | `ListDocuments`, `DocumentStats`, `AddLinks`, `AddWebsite`, `AddSitemap`, `AddYouTube`, `SetText`, `ListSources` |
| `client.Conversations` | `List`, `Get`, `Delete`, `Escalate`                                                                              |
| `client.Leads`         | `List`, `Get`, `Delete`                                                                                          |
| `client.Messages`      | `Send`, `SendToConversation`                                                                                     |
| `client.Onboarding`    | `Start`, `GetWorkspace`                                                                                          |

Plus `client.Me(ctx)` and `client.Health(ctx)`.

### Destructive operations require confirmation

The API requires `confirm=true` on delete-family endpoints, and the SDK keeps
that intent explicit instead of confirming on your behalf: `Chatbots.Delete`,
`Conversations.Delete`, and `Leads.Delete` take a `confirm bool` argument and
return a `CONFIRMATION_REQUIRED` `*sitegpt.Error` locally (before any request)
when it is `false`:

```go theme={null}
_, err := client.Chatbots.Delete(ctx, chatbotID, true)
_, err = client.Conversations.Delete(ctx, chatbotID, threadID, true)
```

## Every other endpoint: `Request`

All API v2 operations are reachable through the low-level `Request`:

```go theme={null}
// Custom responses, personas, instructions, settings, members, tags, billing…
personas, err := client.Request(ctx, http.MethodGet,
	"/api/v2/chatbots/"+chatbotID+"/personas", nil, nil)

_, err = client.Request(ctx, http.MethodPatch,
	"/api/v2/chatbots/"+chatbotID+"/settings", nil, sitegpt.JSON{
		"general": sitegpt.JSON{"title": "Support Bot"},
	})
```

Paths must start with `/`, and the client rejects empty or dot path segments
locally, so a malformed ID can never collapse the URL toward a parent route.
The full endpoint contract is the OpenAPI document at
[sitegpt.ai/api/v2/openapi.json](https://sitegpt.ai/api/v2/openapi.json).

## Timeouts and custom HTTP clients

Requests time out after 10 seconds by default. Pass your own `*http.Client`
to change that — the SDK wraps its redirect policy so the cross-origin
auth-stripping guarantee survives:

```go theme={null}
client := sitegpt.NewClient(token, sitegpt.WithHTTPClient(&http.Client{
	Timeout: 60 * time.Second,
}))
```

Per-call deadlines work through the standard `context` package:

```go theme={null}
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
me, err := client.Me(ctx)
```

## Custom base URL

The base URL defaults to `https://sitegpt.ai` and only needs to change if
SiteGPT gives you a different API origin:

```go theme={null}
client := sitegpt.NewClient(token, sitegpt.WithBaseURL("https://sitegpt.ai"))
```

## Related

* [TypeScript SDK](/docs/developers/sdk-typescript) — the same client for
  TypeScript and JavaScript.
* [Python SDK](/docs/developers/sdk-python) — the same client for Python.
* [SiteGPT CLI](/docs/cli/overview) — the same API from your terminal, scripts,
  and AI agents (includes a local MCP server).
* [API v2 reference](/docs/api-reference/v2/getting-started) — every endpoint,
  generated from the live OpenAPI document.
