> For the complete documentation index, see [llms.txt](https://developer.paddle.com/llms.txt).

# Get started with Paddle in Go

Install the Paddle Go SDK, initialize a client, make your first request, and verify webhook signatures.

---

{% version-badge sdk="paddle-go" /%}

This quickstart walks through installing the Paddle Go SDK, initializing a client, making your first read-only API call, and verifying webhook signatures. The Go SDK is built around `context.Context` throughout — useful for backends that need cancellation, timeouts, and request-scoped values.

## Before you begin

- A [Paddle sandbox account](https://developer.paddle.com/sdks/sandbox.md).
- An [API key](https://developer.paddle.com/api-reference/about/api-keys#create-api-key.md) generated in your sandbox dashboard.
- Go 1.21 or later.

## 1. Install the SDK {% step=true %}

Add the SDK to your Go module:

```sh
go get github.com/PaddleHQ/paddle-go-sdk/v5
```

## 2. Initialize the client {% step=true %}

For sandbox, use `paddle.NewSandbox()`. For production, use `paddle.New()`.

```go
package main

import (
    "log"
    "os"

    paddle "github.com/PaddleHQ/paddle-go-sdk/v5"
)

func main() {
    client, err := paddle.NewSandbox(os.Getenv("PADDLE_API_KEY"))
    if err != nil {
        log.Fatal(err)
    }
    _ = client
}
```

For production, swap `NewSandbox` for `New`:

```go
client, err := paddle.New(os.Getenv("PADDLE_API_KEY"))
```

{% callout type="note" %}
Sandbox API keys contain `_sdbx`. Sandbox and live keys are separate — using one against the other API returns a `forbidden` error.
{% /callout %}

## 3. Make your first request {% step=true %}

List products to confirm the client is wired up. The SDK returns a paginated collection — use `Iter` to walk through results.

```go
package main

import (
    "context"
    "fmt"
    "log"
    "os"

    paddle "github.com/PaddleHQ/paddle-go-sdk/v5"
)

func main() {
    client, err := paddle.NewSandbox(os.Getenv("PADDLE_API_KEY"))
    if err != nil {
        log.Fatal(err)
    }

    ctx := context.Background()
    products, err := client.ListProducts(ctx, &paddle.ListProductsRequest{
        IncludePrices: true,
    })
    if err != nil {
        log.Fatal(err)
    }

    err = products.Iter(ctx, func(p *paddle.Product) (bool, error) {
        fmt.Printf("%s  %s\n", p.ID, p.Name)
        return true, nil
    })
    if err != nil {
        log.Fatal(err)
    }
}
```

Pass a cancellable `context.Context` through your call chain so the SDK can abort in-flight requests when the parent context is cancelled.

## 4. Verify webhooks {% step=true %}

Paddle pushes webhook events to your endpoint when subscriptions, transactions, and customers change state. The Go SDK's `WebhookVerifier` ships with a `Middleware` helper that wraps your handler and rejects unverified requests automatically.

```go
package main

import (
    "log"
    "net/http"
    "os"

    paddle "github.com/PaddleHQ/paddle-go-sdk/v5"
)

func main() {
    verifier := paddle.NewWebhookVerifier(os.Getenv("PADDLE_WEBHOOK_SECRET"))

    handler := verifier.Middleware(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        // Request is verified. Decode and dispatch the event.
        // Best practice: store the event in a queue or DB and return 200 fast.
        w.Header().Set("Content-Type", "application/json")
        w.WriteHeader(http.StatusOK)
        _, _ = w.Write([]byte(`{"success":true}`))
    }))

    http.Handle("/webhooks", handler)
    log.Fatal(http.ListenAndServe(":3000", nil))
}
```

If you'd rather verify manually — for example, to integrate with an HTTP framework that doesn't accept `http.Handler` middleware — call `Verify` directly:

```go
ok, err := verifier.Verify(r)
if err != nil || !ok {
    http.Error(w, "invalid signature", http.StatusBadRequest)
    return
}
```

For the full webhook setup flow — creating notification destinations, picking events, retry behavior — see [Verify webhook signatures](https://developer.paddle.com/webhooks/signature-verification.md).

## Next steps

{% card-group cols=2 %}
{% card title="Build with subscriptions" icon="carbon:repeat" url="/build/subscriptions" %}
Lifecycle, plan changes, pause and resume, addons.
{% /card %}
{% card title="Set up notification destinations" icon="carbon:notification" url="/webhooks/notification-destinations" %}
Configure where Paddle sends webhook events.
{% /card %}
{% card title="API reference" icon="carbon:api" url="/api-reference/overview" %}
Browse every endpoint Paddle exposes.
{% /card %}
{% card title="Go SDK reference" icon="go" url="/sdks/libraries/go" %}
Full SDK reference — version, repo, install, auth.
{% /card %}
{% /card-group %}

{% callout type="note" %}
**Building at scale?** The Go SDK uses `context.Context` throughout — pass cancellation contexts through your call chain so requests abort cleanly on graceful shutdown or upstream cancellation.
{% /callout %}