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

# Go SDK

> Install, configure, and use the LaserSell Go SDK with context.Context patterns for building transactions and streaming positions.

## Installation

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

## Packages

| Package                                        | Purpose                                                            |
| ---------------------------------------------- | ------------------------------------------------------------------ |
| `github.com/lasersell/lasersell-sdk/go`        | `ExitAPIClient`, `SendTarget`, `SignUnsignedTx`, `SendTransaction` |
| `github.com/lasersell/lasersell-sdk/go/stream` | `StreamClient`, `StreamSession`, `StreamConfigure`, message types  |

## API Client

All methods accept a `context.Context` for cancellation and timeouts.

```go theme={null}
package main

import (
    "context"
    "fmt"
    "log"

    lasersell "github.com/lasersell/lasersell-sdk/go"
)

func main() {
    ctx := context.Background()
    client := lasersell.NewExitAPIClientWithAPIKey("YOUR_API_KEY")

    // Build sell
    sellResp, err := client.BuildSellTx(ctx, lasersell.BuildSellTxRequest{
        Mint:         "TOKEN_MINT",
        UserPubkey:   "WALLET",
        AmountTokens: 1_000_000,
        Output:       lasersell.SellOutputSOL,
        SlippageBps:  2_000,
    })
    if err != nil {
        log.Fatal(err)
    }
    fmt.Println("Sell tx:", sellResp.Tx)

    // Build buy
    buyResp, err := client.BuildBuyTx(ctx, lasersell.BuildBuyTxRequest{
        Mint:          "TOKEN_MINT",
        UserPubkey:    "WALLET",
        AmountInTotal: 100_000_000,
        SlippageBps:   2_000,
    })
    if err != nil {
        log.Fatal(err)
    }
    fmt.Println("Buy tx:", buyResp.Tx)
}

// Helper functions for pointer fields (not part of the SDK)
func intPtr(v int) *int       { return &v }
func strPtr(v string) *string { return &v }
```

Optional fields in the Go SDK use pointer types (`*int`, `*string`). The `intPtr` and `strPtr` helpers above are not part of the SDK. Define them in your own code or use inline expressions like `&[]int{2000}[0]`.

### Custom Options

```go theme={null}
opts := lasersell.ExitAPIClientOptions{
    ConnectTimeout: 500 * time.Millisecond,
    AttemptTimeout: 2 * time.Second,
    RetryPolicy: lasersell.RetryPolicy{
        MaxAttempts:    3,
        InitialBackoff: 50 * time.Millisecond,
        MaxBackoff:     200 * time.Millisecond,
        Jitter:         50 * time.Millisecond,
    },
}
client := lasersell.NewExitAPIClientWithOptions("YOUR_API_KEY", opts)
```

## Exit Intelligence Stream Session

```go theme={null}
package main

import (
    "context"
    "errors"
    "fmt"
    "io"
    "log"

    "github.com/gagliardetto/solana-go"
    lasersell "github.com/lasersell/lasersell-sdk/go"
    "github.com/lasersell/lasersell-sdk/go/stream"
)

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

    privateKey, err := solana.PrivateKeyFromSolanaKeygenFile("./keypair.json")
    if err != nil {
        log.Fatal(err)
    }

    client := stream.NewStreamClient("YOUR_API_KEY")
    sendMode := "helius_sender"
    tipLamports := uint64(1000)
    session, err := stream.ConnectSession(ctx, client, stream.StreamConfigure{
        WalletPubkeys: []string{"WALLET_PUBKEY"},
        Strategy: stream.StrategyConfigMsg{
            TargetProfitPct: 5.0,
            StopLossPct:     1.5,
        },
        DeadlineTimeoutSec: 45,
        SendMode:           &sendMode,
        TipLamports:        &tipLamports,
    })
    if err != nil {
        log.Fatal(err)
    }

    for {
        event, err := session.Recv(ctx)
        if errors.Is(err, io.EOF) {
            break
        }
        if err != nil {
            log.Fatal(err)
        }

        switch msg := event.Message.(type) {
        case stream.PositionOpenedServerMessage:
            fmt.Printf("New position: %s\n", msg.Mint)

        case stream.ExitSignalWithTxServerMessage:
            signedTx, err := lasersell.SignUnsignedTx(msg.UnsignedTxB64, privateKey)
            if err != nil {
                log.Printf("Sign error: %v", err)
                continue
            }
            sig, err := lasersell.SendTransaction(
                ctx, nil, lasersell.SendTargetHeliusSender(), signedTx,
            )
            if err != nil {
                log.Printf("Send error: %v", err)
                continue
            }
            fmt.Printf("Exit submitted: %s\n", sig)

        case stream.ErrorServerMessage:
            log.Printf("Stream error: code=%s message=%s", msg.Code, msg.Message)
        }
    }
}
```

## Liquidity Snapshots and Partial Sells

<Note>
  **Tier 1+ only.** Requires a Professional or Advanced subscription. See the [announcement](https://www.lasersell.io/blog/liquidity-snapshots-and-sdk-0-3) for full details.
</Note>

`StreamSession` caches the latest liquidity snapshot per position. Query slippage bands, maximum sellable amounts, and liquidity trends:

```go theme={null}
bands := session.GetSlippageBands(positionID)
maxTokens := session.GetMaxSellAtSlippage(positionID, 500) // 5% slippage
trend := session.GetLiquidityTrend(positionID) // "growing" | "stable" | "draining"
```

Use `BuildPartialSellTx()` to sell a portion of a position based on slippage data:

```go theme={null}
maxTokens := session.GetMaxSellAtSlippage(positionID, 500)
if maxTokens != nil {
    response, err := client.BuildPartialSellTx(ctx, handle, *maxTokens, 500, lasersell.SellOutputSOL)
}
```

## Mirror Trading

Configure watch wallets to mirror trades from other wallets. When a watched wallet opens a position on a supported market, the stream sends a `MirrorBuySignalServerMessage` with an unsigned transaction for your wallet to execute.

```go theme={null}
package main

import (
    "context"
    "errors"
    "fmt"
    "io"
    "log"

    "github.com/gagliardetto/solana-go"
    lasersell "github.com/lasersell/lasersell-sdk/go"
    "github.com/lasersell/lasersell-sdk/go/stream"
)

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

    privateKey, err := solana.PrivateKeyFromSolanaKeygenFile("./keypair.json")
    if err != nil {
        log.Fatal(err)
    }

    walletPubkey := "YOUR_WALLET_PUBKEY"

    sendMode := "helius_sender"
    tipLamports := uint64(1000)
    session, err := stream.ConnectSession(ctx, stream.NewStreamClient("YOUR_API_KEY"), stream.StreamConfigure{
        WalletPubkeys: []string{walletPubkey},
        Strategy: stream.StrategyConfigMsg{
            TargetProfitPct: 50.0,
            StopLossPct:     25.0,
        },
        DeadlineTimeoutSec: 45,
        SendMode:           &sendMode,
        TipLamports:        &tipLamports,
        WatchWallets: []stream.WatchWalletConfig{
            {
                Pubkey: "WatchedWalletPubkey...",
                AutoBuy: &stream.AutoBuyConfig{
                    WalletPubkey:    walletPubkey,
                    AmountQuoteUnits: intPtr(100_000_000),
                },
                MirrorSell: false,
            },
        },
        MirrorConfig: &stream.MirrorConfig{
            MaxPositionsPerWallet: 1,
            CooldownSec:          30,
            MaxActiveSOL:         5.0,
            BuySlippageBps:       2500,
        },
    })
    if err != nil {
        log.Fatal(err)
    }

    for {
        event, err := session.Recv(ctx)
        if errors.Is(err, io.EOF) {
            break
        }
        if err != nil {
            log.Fatal(err)
        }

        switch msg := event.Message.(type) {
        case stream.MirrorBuySignalServerMessage:
            signedTx, err := lasersell.SignUnsignedTx(msg.UnsignedTxB64, privateKey)
            if err != nil {
                log.Printf("Sign error: %v", err)
                continue
            }
            sig, err := lasersell.SendTransaction(
                ctx, nil, lasersell.SendTargetHeliusSender(), signedTx,
            )
            if err != nil {
                log.Printf("Send error: %v", err)
                continue
            }
            session.Sender().MirrorBuyResult(msg.Mint, true)
            fmt.Printf("Mirror buy submitted: %s\n", sig)

        case stream.MirrorBuyFailedServerMessage:
            log.Printf("Mirror buy failed: %s", msg.Reason)

        case stream.ExitSignalWithTxServerMessage:
            signedTx, err := lasersell.SignUnsignedTx(msg.UnsignedTxB64, privateKey)
            if err != nil {
                log.Printf("Sign error: %v", err)
                continue
            }
            sig, err := lasersell.SendTransaction(
                ctx, nil, lasersell.SendTargetHeliusSender(), signedTx,
            )
            if err != nil {
                log.Printf("Send error: %v", err)
                continue
            }
            fmt.Printf("Exit submitted: %s\n", sig)
        }
    }
}

func intPtr(v int) *int { return &v }
```

The `WatchWallets` slice specifies which wallets to mirror. Each `WatchWalletConfig` includes an `AutoBuy` configuration that controls how much to spend when mirroring a trade, and a `MirrorSell` flag that determines whether to also mirror sell transactions.

The `MirrorConfig` struct sets global limits: `MaxPositionsPerWallet` caps concurrent mirrored positions, `CooldownSec` enforces a delay between mirror buys, `MaxActiveSOL` limits total SOL exposure, and `BuySlippageBps` sets the slippage tolerance for mirror buy transactions.

## Transaction Helpers

The second parameter to `SendTransaction` is an `*http.Client`. Pass `nil` to use the SDK's default HTTP client.

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

// Sign
signedTx, err := lasersell.SignUnsignedTx(unsignedTxB64, privateKey)

// Send via Helius Sender (nil = use default HTTP client)
sig, err := lasersell.SendTransaction(ctx, nil, lasersell.SendTargetHeliusSender(), signedTx)

// Send via custom RPC
sig, err = lasersell.SendTransaction(ctx, nil,
    lasersell.SendTargetRpc("https://rpc.example.com"), signedTx)

// Send via Astralane
sig, err = lasersell.SendTransaction(ctx, nil,
    lasersell.SendTargetAstralane("KEY", "fr"), signedTx)

// With a custom HTTP client
customClient := &http.Client{Timeout: 5 * time.Second}
sig, err = lasersell.SendTransaction(ctx, customClient,
    lasersell.SendTargetHeliusSender(), signedTx)
```

## Error Handling

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

resp, err := client.BuildSellTx(ctx, request)
if err != nil {
    var apiErr *lasersell.ExitAPIError
    if errors.As(err, &apiErr) {
        fmt.Println("Kind:", apiErr.Kind)
        fmt.Println("Retryable:", apiErr.IsRetryable())
        fmt.Println("Status:", apiErr.Status)
    }
}
```

## `context.Context` Patterns

All Go SDK methods accept `context.Context` as their first argument. Use this to control:

* **Timeouts**: `context.WithTimeout(ctx, 5*time.Second)`
* **Cancellation**: `context.WithCancel(ctx)` for graceful shutdown
* **Deadlines**: `context.WithDeadline(ctx, time.Now().Add(30*time.Second))`

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

resp, err := client.BuildSellTx(ctx, request)
```

## Complete Example

See the [Quickstart](/api/quickstart) for a full working example.
