---
title: "Registering a Payout Address"
canonical: "https://test.abhinandan.one/x402-payments-overview-04a296ff/go-x402-register-payout"
markdown_url: "https://test.abhinandan.one/x402-payments-overview-04a296ff/go-x402-register-payout.md"
publisher: "Primitive SDKs"
kind: "guide"
content_type: "reference"
category: "Go SDK"
parent: "x402-payments-overview-04a296ff"
description: "Register a default x402 payout address in Go with RegisterPayoutAddress by signing a local ownership message with your wallet's private key."
keywords: ["RegisterPayoutAddress", "x402 payout address registration", "BuildPayoutRegistrationMessage", "NewPrivateKeySigner", "X402Client Go", "pay_to resolution"]
last_modified: "2026-08-21T18:22:43.359885+00:00"
published_at: "2026-08-11T18:54:57.685639+00:00"
source_files:
  - "sdk-go/x402.go"
  - "sdk-go/README.md"
sections:
  - {anchor: "what-the-registration-proves", title: "What the registration proves"}
  - {anchor: "prerequisites", title: "Prerequisites"}
  - {anchor: "step-construct-the-x402-client", title: "Construct the x402 client"}
  - {anchor: "step-build-a-signer-from-your-private-key", title: "Build a signer from your private key"}
  - {anchor: "step-register-the-address", title: "Register the address"}
  - {anchor: "step-verify-it-landed", title: "Verify it landed"}
  - {anchor: "networks", title: "Networks"}
  - {anchor: "errors", title: "Errors"}
  - {anchor: "next-steps", title: "Next steps"}
---

> Documentation index: https://test.abhinandan.one/llms.txt

# Registering a Payout Address

Prove control of a wallet with a local ownership signature and register it as your org's default x402 payout destination on a given network, a one-time step before you can call Charge.

Register a payout address once, per network, before you call `Charge`. The registration proves you control a wallet by signing an ownership message locally with your private key; the recovered address becomes the `pay_to` destination `Charge` resolves automatically for every future challenge on that network.

Do this the first time you set up payments as a payee, and again whenever you want to change which wallet receives funds on a given network. You don't need it to pay a challenge, only to receive.

> **Note:** x402 payments are non-custodial: your private key never leaves your machine, and Primitive never holds funds. For the full payment model (charge → pay → settle) and terminology, see [x402 Payments Overview](https://test.abhinandan.one/x402-payments-overview.md).

## What the registration proves

Registration proves you control the wallet: it sends a locally signed ownership message, never your private key.

`RegisterPayoutAddress` posts that signature alongside the address. The message is built by `BuildPayoutRegistrationMessage(org, address, network, issuedAt)` and must be byte-identical to what the platform recomputes:

```text
Primitive x402 payout address authorization

I authorize this address as a payout destination for my Primitive organization.

org: <org-id>
address: <lowercased address>
network: <network>
issued: <issued-at>
```

Your organization id is embedded in the signed bytes. That means a captured signature can never be replayed to register the address under a different org. The org id is resolved automatically from your API key, so you never set it yourself; the `X402ClientOptions.APIKey` you construct the client with determines it.

## Prerequisites

You need a Primitive API key, a wallet private key in an environment variable, and the Go SDK installed.

- A Primitive API key (`prim_test` in examples, or your production key via `PRIMITIVE_API_KEY`).
- A wallet private key for the address you want paid, in an environment variable such as `PAYEE_KEY`. Never hardcode it.
- The Go SDK installed: `go get github.com/primitivedotdev/sdks/sdk-go@latest`.

### 1. Construct the x402 client

Build a client from your API key. With zero options it reads `PRIMITIVE_API_KEY` from the environment and targets the production host.

```go
package main

import (
	"context"
	"log"
	"os"

	primitive "github.com/primitivedotdev/sdks/sdk-go"
)

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

	client := primitive.NewX402Client(primitive.X402ClientOptions{
		APIKey: os.Getenv("PRIMITIVE_API_KEY"),
	})
	_ = ctx
	_ = client
}
```

### 2. Build a signer from your private key

`NewPrivateKeySigner` holds the wallet key in process memory and never sends it to Primitive. It signs both the EIP-712 payment authorization (used by `Pay`) and the personal-sign ownership message (used here).

```go
payee, err := primitive.NewPrivateKeySigner(os.Getenv("PAYEE_KEY"))
if err != nil {
	log.Fatal(err)
}
```

### 3. Register the address

Call `RegisterPayoutAddress` with the target network and, optionally, a human-readable label. Leave `Org` unset unless you need to override the organization resolved from your API key.

```go
label := "treasury"
result, err := client.RegisterPayoutAddress(ctx, primitive.X402PayoutRegistrationInput{
	Network: "base-sepolia",
	Label:   &label,
}, payee)
if err != nil {
	log.Fatal(err)
}
```

### 4. Verify it landed

List your registered payout addresses to confirm the new default:

```go
addresses, err := client.ListPayoutAddresses(ctx)
if err != nil {
	log.Fatal(err)
}
for _, a := range addresses {
	log.Println(a)
}
```

A successful registration means later calls to `Charge` on that network resolve `PayTo` to this address automatically; you never pass a payout address on `Charge` itself.

## Networks

Two networks are supported: `"base-sepolia"` (testnet, used in these examples) and `"base"` (mainnet). Register separately per network; a registration on one network does not carry over to the other.

> **Warning:** Registering a new default address for a network replaces the previous one for future challenges. Any challenge already created before the change keeps its original `pay_to`.

> **Tip:** You only register a payout address as the **payee**. If you're the payer signing and settling someone else's challenge, skip this step entirely; see [x402 Payments Overview](https://test.abhinandan.one/x402-payments-overview.md) for the payer side of the flow.

## Errors

Every method on `X402Client`, including `RegisterPayoutAddress`, returns a `*primitive.X402Error` on a client-side, transport, or non-2xx server error. Use `errors.As` to inspect it:

```go
import (
	"errors"
	"log"

	primitive "github.com/primitivedotdev/sdks/sdk-go"
)

var xerr *primitive.X402Error
if errors.As(err, &xerr) {
	log.Printf("status=%d retryAfter=%v body=%v", xerr.Status, xerr.RetryAfter, xerr.Body)
}
```

`Status` is `0` when the request never reached the server (a DNS failure, a connection error, or a client-side timeout), distinct from a 4xx/5xx the server actually returned. See [x402 Errors](https://test.abhinandan.one/x402-payments-overview-04a296ff/go-x402-errors.md) for the full breakdown of status codes and retry semantics.
