# Authentication

Configure Ed25519 API keys, Account ID, and env-based wiring for bots.

Programmatic access uses **Ed25519 API keys**. The SDK signs authenticated ConnectRPC requests and fetches private realtime tokens for you.

## Recommended: explicit credentials

```go
accountID := "..." // Profile → Account ID
client, err := polyester.New(polyester.Config{
    APIKeyID:         "ak_...",
    APIPrivateKey:    "...", // 64-char hex from key creation
    DefaultAccountID: &accountID,
    HydrateCatalogs:  true,
})
if err != nil { log.Fatal(err) }
defer client.Close()
ctx := context.Background()
if err := client.WaitForCatalogs(ctx); err != nil { log.Fatal(err) }
```

## Environment variables

Read secrets in your process and pass them in:

```go
accountID := os.Getenv("POLYESTER_ACCOUNT_ID")
client, err := polyester.New(polyester.Config{
    APIKeyID:         os.Getenv("POLYESTER_API_KEY_ID"),
    APIPrivateKey:    os.Getenv("POLYESTER_API_PRIVATE_KEY"),
    DefaultAccountID: &accountID,
    HydrateCatalogs:  true,
})
```

For scripts only, `polyester.FromEnv()` loads credentials and Account ID. It does **not** load API/WebSocket URL overrides, set `APIURL` / `WSURL` on `Config` explicitly. Prefer explicit `Config` in production.

| Variable                                 | Purpose                                                       |
| ---------------------------------------- | ------------------------------------------------------------- |
| `POLYESTER_API_KEY_ID`                   | API key id                                                    |
| `POLYESTER_API_PRIVATE_KEY`              | 64-char hex private key                                       |
| `POLYESTER_ACCOUNT_ID`                   | Profile Account ID                                            |
| `POLYESTER_API_URL` / `POLYESTER_WS_URL` | Not loaded by `FromEnv`, set `Config.APIURL` / `Config.WSURL` |

> **Never commit secrets**
>
> Use placeholders in docs and samples. Store production keys in your secret manager.

## Generate a keypair

```go
pair := client.APIKeys.GenerateKeypair()
```

Local key material only. Listing and subscribing to keys uses `client.APIKeys` with an API key. **Creating** API keys is JWT/session-only (TypeScript / browser), not exposed on this SDK.

See [API keys](https://testnet.polyester.com/docs/sdk/go/reference/api-keys).

## Public vs private

- Public market data works with no key.
- Private RPCs and private WebSocket channels need a key **and** Account ID.
- Streams: use `Messages()`, Go has no `Recv()`.

## Subaccount scope

Set `DefaultSubAccountID` for default scoping, or pass per-call account scope where the service supports it.

Concept: [Authentication model](https://testnet.polyester.com/docs/sdk/go/concepts/authentication-model). Config: [Client configuration](https://testnet.polyester.com/docs/sdk/go/reference/client-configuration).
