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

# Go SDK

> Go client for the Octavia AI CMS API.

Go 1.21+, a single module with zero dependencies outside the standard library. Every
method returns `(*CMSResponse, error)`.

<Note>
  This is the most complete SDK: it is generated from the OpenAPI spec, so it covers
  every public operation, including AI conversation, meta and tags.
</Note>

## Install

```bash theme={null}
go get github.com/octaviatech/cms-sdk-go
```

## Initialize

```go theme={null}
package main

import (
	"log"
	"time"

	"github.com/octaviatech/cms-sdk-go/sdk"
)

func main() {
	cms, err := sdk.InitCMS(os.Getenv("OCTAVIA_API_KEY"), &sdk.CMSOptions{
		Timeout: 30 * time.Second,
	})
	if err != nil {
		log.Fatal(err)
	}
	_ = cms
}
```

`InitCMS` returns an error, so always check it. The key is sent as the `x-api-key`
header on every request; there is no header option, by design.

For more control, build a `Client` directly:

```go theme={null}
client, err := sdk.NewClient(sdk.ClientConfig{
	BaseURL: sdk.CMSBaseURL,
	ApiKey:  key,
	Timeout: 30 * time.Second,
})
```

`Timeout` defaults to 30 seconds when left zero.

## Make a request

Read operations that take filters take a single map:

```go theme={null}
res, err := cms.Article.GetAll(map[string]interface{}{
	"page": 1, "limit": 10,
})
if err != nil {
	log.Fatal(err)
}

if res.Ok {
	fmt.Println(res.Data)
	fmt.Println(res.Meta)
} else {
	fmt.Println(res.Error.Message)
}
```

Single-resource and search operations use the same shape:

```go theme={null}
one    := cms.Article.GetById("6810f2c3a1b2c3d4e5f60718")
hits   := cms.Article.Search(map[string]interface{}{"query": "typescript"})
bySlug := cms.Article.GetBySlug("hello-world")
```

<Note>
  `res.Data` is `interface{}` decoded from JSON, typically a `map[string]interface{}`.
  Marshal it back through `encoding/json` to get typed structs, or define your own
  types and unmarshal into them.
</Note>

## Write operations

```go theme={null}
created, err := cms.Article.Create(map[string]interface{}{
	"title":      "Hello world",
	"body":       "...",
	"categoryId": "6810f2c3a1b2c3d4e5f60712",
	"authorId":   "6810f2c3a1b2c3d4e5f60719",
})
if err != nil {
	log.Fatal(err)
}

id := created.Data.(map[string]interface{})["id"].(string)

_, _ = cms.Article.Update(id, map[string]interface{}{"title": "Updated"})
_, _ = cms.Article.Delete(id)
```

## Error handling

Two kinds of error, and they are different things:

* `error` is a **transport** problem — DNS, TLS, timeout. Nothing was processed.
* `res.Ok == false` is an **API** response. The request succeeded, the server said no.

```go theme={null}
res, err := cms.Article.GetById("does-not-exist")

switch {
case err != nil:
	// transport failure
	log.Fatal(err)
case !res.Ok:
	// API said 404
	fmt.Println(res.Error.Status, res.Error.Message)
}
```

`ThrowOnError` does something different from the other SDKs — it **panics**, and the
panic value is a plain string, not a typed `ApiError`:

```go theme={null}
cms, _ := sdk.InitCMS(key, &sdk.CMSOptions{ThrowOnError: true})

defer func() {
	if r := recover(); r != nil {
		log.Printf("request failed: %v", r)
	}
}()
```

<Warning>
  Prefer checking `res.Ok`. Enabling `ThrowOnError` costs you the typed error — the
  status code and payload are discarded in the panic.
</Warning>

## Context and cancellation

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

res, err := cms.Article.GetAllWithContext(ctx, map[string]interface{}{"page": 1})
```

## Escaping the resource wrapper

`cms.Raw` is the underlying client:

```go theme={null}
res, err := cms.Raw.Request("GET", "/articles/advancedSearch", nil)
```

## Resources

`Article`, `Author`, `Category`, `Subcategory`, `Form`, `FormSubmission`, `Language`,
`Tag`, `Report`, `AI`, `AIConversation`, `Raw`.

<Card title="All operations" icon="list" href="/api-reference/ai-cms/articles/get-all" arrow="true">
  Browse the API reference for the full endpoint list.
</Card>
