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

# WebSocket Client

> Real-time subscriptions for account changes, logs, slots, and signatures with auto-reconnect.

## Install

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

```go theme={null}
import "github.com/orbitflare/orbitflare-sdk-go/ws"
```

## Building the client

```go theme={null}
import (
    "time"

    "github.com/orbitflare/orbitflare-sdk-go/orbitflare"
    "github.com/orbitflare/orbitflare-sdk-go/ws"
)

client, err := ws.NewBuilder().
    URL("ws://ny.rpc.orbitflare.com").
    FallbackURL("ws://fra.rpc.orbitflare.com").
    APIKey("ORBIT-XXXXXX-NNNNNN-NNNNNN").
    Retry(orbitflare.RetryPolicy{
        InitialDelay: 100 * time.Millisecond,
        MaxDelay:     30 * time.Second,
        Multiplier:   2.0,
        MaxAttempts:  0,
    }).
    PingInterval(10 * time.Second).
    MaxMissedPongs(3).
    Build(ctx)
```

Minimal:

```go theme={null}
client, err := ws.NewBuilder().
    URL("ws://ny.rpc.orbitflare.com").
    Build(ctx)
```

Note that `.Build(ctx)` establishes the WebSocket connection before returning - the passed context governs the initial dial. If the connection fails, you get the error immediately. The client then runs until `Close()`.

### Builder methods

**`.URL(url)`** - Primary WebSocket endpoint. Falls back to `ORBITFLARE_WS_URL` env var.

```go theme={null}
.URL("ws://ny.rpc.orbitflare.com")
```

**`.URLs(urls...)`** - Primary + fallbacks in one call.

```go theme={null}
.URLs("ws://ny.rpc.orbitflare.com", "ws://fra.rpc.orbitflare.com")
```

**`.FallbackURL(url)` / `.FallbackURLs(urls...)`** - Add failover endpoints. On reconnect, the SDK rotates through them.

```go theme={null}
.FallbackURL("ws://fra.rpc.orbitflare.com")
```

**`.APIKey(key)`** - License key. Falls back to `ORBITFLARE_LICENSE_KEY` env var. Injected into the URL at connect time, never printed in logs or errors.

```go theme={null}
.APIKey("ORBIT-XXXXXX-NNNNNN-NNNNNN")
```

**`.Retry(policy)`** - Reconnection backoff. Default: 100ms initial, 30s max, 2x multiplier, infinite attempts.

```go theme={null}
.Retry(orbitflare.RetryPolicy{
    InitialDelay: 200 * time.Millisecond,
    MaxDelay:     15 * time.Second,
    Multiplier:   2.0,
    MaxAttempts:  0,
})
```

**`.PingInterval(duration)`** - How often the SDK sends WebSocket `Ping` frames. Default: 10s.

```go theme={null}
.PingInterval(15 * time.Second)
```

**`.MaxMissedPongs(n)`** - Pings without a response before killing the connection. Default: 3.

```go theme={null}
.MaxMissedPongs(5)
```

**`.Logger(logger)`** - A `*slog.Logger` for connection lifecycle events. When unset, controlled by `ORBITFLARE_LOG`.

## Available subscriptions

### `SlotSubscribe(ctx)`

Fires every time a slot is processed, confirmed, or finalized.

```go theme={null}
sub, err := client.SlotSubscribe(ctx)
```

Each event is JSON with `slot`, `parent`, and `root` fields:

```json theme={null}
{"slot": 413014740, "parent": 413014739, "root": 413014708}
```

### `AccountSubscribe(ctx, address, commitment)`

Fires when the specified account's data changes.

```go theme={null}
sub, err := client.AccountSubscribe(ctx, "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", "confirmed")
```

Returns base64-encoded account data with lamports, owner, and executable flag.

### `LogsSubscribe(ctx, mentions, commitment)`

Fires for transactions that mention the given addresses. Pass an empty slice for all transactions.

```go theme={null}
sub, err := client.LogsSubscribe(ctx, []string{"6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P"}, "confirmed")
```

All logs:

```go theme={null}
sub, err := client.LogsSubscribe(ctx, nil, "confirmed")
```

### `SignatureSubscribe(ctx, signature, commitment)`

Fires once when a transaction reaches the given commitment level. Useful for confirming a transaction you just sent.

```go theme={null}
sub, err := client.SignatureSubscribe(ctx, "5K8F2j...", "confirmed")
```

## Reading events

All subscriptions return a `*ws.Subscription`. Call `Next(ctx)` to get the next event:

```go theme={null}
for {
    event, ok := sub.Next(ctx)
    if !ok {
        break // context cancelled or client shut down
    }
    fmt.Println(string(event))
}
```

`Next(ctx)` returns `(json.RawMessage, bool)`. When `ok` is false the subscription is finished (the context was cancelled or the client closed).

## Unsubscribing

```go theme={null}
sub.Unsubscribe()
```

This sends an unsubscribe message to the server. If you stop reading a subscription without calling this, the SDK detects the orphan and sends the unsubscribe automatically.

## Multiple subscriptions

All subscriptions run on a single WebSocket connection. The SDK routes notifications to the right subscription internally.

```go theme={null}
slots, _ := client.SlotSubscribe(ctx)
usdc, _ := client.AccountSubscribe(ctx, "EPjFWdd5...", "confirmed")
logs, _ := client.LogsSubscribe(ctx, []string{"6EF8r..."}, "confirmed")
```

You can add new subscriptions at any time while existing ones are running.

## Reconnection

If the connection drops, the background goroutine reconnects with exponential backoff and re-subscribes everything automatically. Your `Next(ctx)` calls just keep working - events resume once the connection is back.

## Full example

A monitoring program that subscribes to slot updates and USDC account changes, printing a live feed.

```go theme={null}
package main

import (
    "context"
    "encoding/json"
    "fmt"
    "log"

    "github.com/orbitflare/orbitflare-sdk-go/ws"
)

func main() {
    ctx := context.Background()

    client, err := ws.NewBuilder().
        URL("ws://ny.rpc.orbitflare.com").
        Build(ctx)
    if err != nil {
        log.Fatal(err)
    }
    defer client.Close()

    slots, err := client.SlotSubscribe(ctx)
    if err != nil {
        log.Fatal(err)
    }
    defer slots.Unsubscribe()

    fmt.Println("watching slots...")
    for {
        event, ok := slots.Next(ctx)
        if !ok {
            return
        }
        var slot struct {
            Slot   uint64 `json:"slot"`
            Parent uint64 `json:"parent"`
        }
        json.Unmarshal(event, &slot)
        fmt.Printf("slot %d (parent %d)\n", slot.Slot, slot.Parent)
    }
}
```
