# Go SDK

(Coming soon)

`koo-go` is a framework-free, typed Go client for the [Koo API](/docs/developers/api). You construct a client with `koo.NewClient(baseURL, token)` — authenticating with a `kc_…` [API token](/docs/developers/api-tokens) — and navigate a typed scope chain from account down to a single service. Every method takes a `context.Context` as its first argument and returns a value or a typed `*KooError`. It is generated from the same OpenAPI spec as the [Node SDK](/docs/developers/sdk-node) and the [API reference](/api), so all three stay in lockstep.

> **Note:**
>
> The Go SDK is code-complete and verified in its repository, but the module has not been published to its public import host (`github.com/koo-io/koo-go`) yet — the `go get` command below will work once it is. Until then, everything the SDK does is available over plain HTTPS with a `kc_…` token (see [Until then](#until-then)).

```bash
go get github.com/koo-io/koo-go
```

Requires Go 1.24 or newer.

## Authenticate

The SDK authenticates with a `kc_…` service-account token — read it from the environment, never hard-code it. Use `Whoami` to confirm who you're acting as; unlike the browser's `/me`, it works with a service-account token and tells you the single account the token is confined to.

```go
import (
	"context"
	"os"

	koo "github.com/koo-io/koo-go"
)

client, err := koo.NewClient("https://api.koo.io", os.Getenv("KOO_TOKEN"))
if err != nil {
	return err
}

who, err := client.Whoami(context.Background())
if err != nil {
	return err
}
if who.Kind != koo.WhoamiKindServiceAccount {
	return fmt.Errorf("use a kc_ service-account token")
}
accountID := who.ServiceAccount.AccountID
```

## The scope chain

The client mirrors the API's shape: an account holds projects, a project holds environments, and an environment holds services. Descend with `.Account(id).Project(id).Environment(id).Service(name)`; each hop returns a typed scope value.

```go
account := client.Account(accountID)

project, err := account.Projects().Create(ctx, koo.CreateProjectDto{Name: "web"})
env, err := account.Project(project.Id).Environments().Create(ctx, koo.CreateEnvironmentDto{Name: "prod"})
```

Every method takes a trailing `...koo.CallOption` (today, `koo.WithIdempotencyKey`) and returns the decoded body. The full surface:

```
client.Whoami(ctx) / client.Me(ctx)
client.Account(accountID)
    .Get(ctx) · .Tokens(){ List, Create, Revoke } · .Projects(){ List, Create }
    .Project(projectID)
        .Get(ctx) · .Environments(){ List, Create }
        .Environment(environmentID)
            .Get(ctx) · .Services(){ List, Create }
            .Service(name)
                .Get(ctx) · .Deploy() · .Rollback() · .DeployFromArchive()
                .Deployments(){ List, BuildLogs } · .Uploads(){ Create }
                .Logs() · .Metrics()
```

## Deploy and watch it roll out

```go
svc := client.Account(accountID).Project(project.Id).Environment(env.Id).Service("api")

dep, err := svc.Deploy(ctx, koo.CreateDeploymentDto{Image: koo.Ptr("ghcr.io/acme/api:sha")})
// The deployment status advances through a fixed pipeline:
//   queued → building → built → applied   (image deploys skip the build phases)
```

Poll `svc.Deployments().List(ctx, nil)` until your deployment's `Status` is `applied` — that means the release is on the platform. It is **not** a health verdict: read `svc.Get(ctx)` and watch `Status.Health` reach `online` (the service is running).

## Errors

Every call returns a `*KooError` on failure, carrying a stable `Code`, a human `Message`, optional `Details`, the HTTP `Status`, and a `RequestID` (from the response's `X-Request-Id` header) to quote to support. Read it with `errors.As`:

```go
_, err := svc.Deploy(ctx, koo.CreateDeploymentDto{})
var kerr *koo.KooError
if errors.As(err, &kerr) {
	log.Printf("[%s] %s — reference %s", kerr.Code, kerr.Message, kerr.RequestID)
}
```

## Retries and idempotency

The SDK retries transient failures for you. Idempotent verbs (`GET`/`HEAD`/`PUT`/`DELETE`) and any `POST` carrying an `Idempotency-Key` are retried on network errors, `429`, and `5xx`, with full-jitter exponential backoff that honours `Retry-After`. A `4xx` other than `429` — including `401`/`403` — fails fast on the first request, with no loop.

By default the SDK stamps a stable `Idempotency-Key` on `POST`s so they are safe to retry (the server dedups the write). Pass your own with `koo.WithIdempotencyKey(key)`, or disable auto-stamping with `koo.WithAutoIdempotency(false)`. This is the same policy the Node SDK implements — both are held to a shared conformance vector file.

## Until then

The REST API the SDK wraps is already live and documented: the [API overview](/docs/developers/api) covers authentication, errors, and pagination, and the [API reference](/api) documents every endpoint. Calling the API from your own code today takes a `kc_…` [API token](/docs/developers/api-tokens) — so everything the SDK will do is already available over plain HTTPS from Go with `net/http`, and the [CLI](/docs/developers/cli) drives Koo from your terminal in the meantime.

## Related

- 
- 
- 
-
