# Go SDK

The official server-side Go SDK. The API mirrors the official Mixpanel Go SDK (`mixpanel-go`), so migrating is mostly a matter of swapping the import. Go 1.22+, zero dependencies, context-based.

## Install

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

## Initialize

```go
package main

import (
	"context"

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

func main() {
	client := cohorly.NewClient("YOUR_PROJECT_TOKEN",
		cohorly.WithAPIHost("https://cohorly-service.velloalabs.com"))

	ctx := context.Background()
	err := client.Track(ctx, []*cohorly.Event{
		client.NewEvent("signup", "user-1", map[string]any{
			"plan": "premium",
		}),
	})
	if err != nil {
		// handle error
	}
}
```

## API

| Member                                                                     | Notes                                                                                                            |
| -------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------- |
| `NewClient(token, opts...)`                                                | Options: `WithAPIHost`, `WithHTTPClient`.                                                                        |
| `client.NewEvent(name, distinctID, props)`                                 | Stamps `time` (unix ms), `$insert_id`, `$lib`, `$lib_version`. `AddTime` / `AddInsertID` override for backfills. |
| `Track(ctx, events)`                                                       | Chunks transparently at the server's 500-event batch cap. Batches are atomic server-side, safe to retry as-is.   |
| `PeopleSet / PeopleSetOnce / PeopleIncrement / PeopleUnset / PeopleDelete` | Profile updates mapped to /engage ops.                                                                           |
| `Alias(ctx, alias, distinctID)`                                            | POST /alias.                                                                                                     |
| `NewBufferedClient(client, opts...)`                                       | Non-blocking `Enqueue` + background flush loop with the shared retry contract. `Close(ctx)` on shutdown.         |

## Buffered mode

```go
buffered := cohorly.NewBufferedClient(client,
	cohorly.WithFlushInterval(10*time.Second),
	cohorly.WithFlushBatchSize(50),
)

buffered.Enqueue(buffered.NewEvent("page_view", "user-1", nil))

// On shutdown: stop the loop and flush whatever is left.
if err := buffered.Close(ctx); err != nil {
	// remaining events could not be delivered
}
```

The buffered client implements the shared Cohorly retry contract:
exponential backoff on 429/5xx/network honoring
`Retry-After`, batch halving on 413, permanent drop on 400,
queue capped at 1000 (oldest dropped). It embeds
`*Client`, so the synchronous methods stay available.

## Error handling

```go
err := client.Track(ctx, events)
if errors.Is(err, cohorly.ErrInvalidToken) {
	// bad project token (HTTP 401)
}
var httpErr *cohorly.HTTPError
if errors.As(err, &httpErr) && httpErr.Status == 429 {
	time.Sleep(httpErr.RetryAfter)
	// safe to retry the same payload
}
```
