---
title: "x402 Spend Policy (Go SDK)"
canonical: "https://test.abhinandan.one/x402-payments-overview-04a296ff/go-x402-spend-policy"
markdown_url: "https://test.abhinandan.one/x402-payments-overview-04a296ff/go-x402-spend-policy.md"
publisher: "Primitive SDKs"
kind: "guide"
content_type: "reference"
category: "Go SDK"
parent: "x402-payments-overview-04a296ff"
description: "Cap, pause, or allowlist outbound x402 payments in the Go SDK with X402Client.SetSpendPolicy and its builder methods."
keywords: ["SetSpendPolicy", "X402SpendPolicyUpdate", "ClearMaxPerPayment", "ClearMaxPerDay", "ListPayoutAddresses", "spend policy Go SDK"]
last_modified: "2026-08-21T18:22:43.359885+00:00"
published_at: "2026-08-11T18:54:59.562342+00:00"
source_files:
  - "sdk-go/README.md"
  - "sdk-go/x402.go"
sections:
  - {anchor: "what-the-spend-policy-guards", title: "What the spend policy guards"}
  - {anchor: "read-the-current-policy", title: "Read the current policy"}
  - {anchor: "step-construct-the-x402-client", title: "Construct the x402 client"}
  - {anchor: "step-inspect-the-fields", title: "Inspect the fields"}
  - {anchor: "update-the-policy", title: "Update the policy"}
  - {anchor: "step-pause-outbound-payments-kill-switch", title: "Pause outbound payments (kill-switch)"}
  - {anchor: "step-set-a-per-payment-cap", title: "Set a per-payment cap"}
  - {anchor: "step-clear-a-cap", title: "Clear a cap"}
  - {anchor: "list-registered-payout-addresses", title: "List registered payout addresses"}
  - {anchor: "errors", title: "Errors"}
  - {anchor: "next-steps", title: "Next steps"}
---

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

# x402 Spend Policy (Go SDK)

Guard outbound x402 payments with a paused kill-switch, per-payment and daily USDC caps, and a payee allowlist using the Go SDK's SetSpendPolicy.

## What the spend policy guards

The [spend policy](https://test.abhinandan.one/x402-payments-overview.md) is the org-level guardrail on outbound x402 payments: a `Paused` kill-switch, per-payment and daily caps in token base units (or `nil` for no cap), and an allowlist of payee orgs (`nil` means any on-net payee, an empty slice denies all). Set it before you let an agent pay challenges unattended, so a bug or a compromised key can't spend beyond what you've bounded.

Read it with `client.GetSpendPolicy(ctx)` and change it with `client.SetSpendPolicy(ctx, update)`. Payout registration is covered in [Registering a Payout Address](https://test.abhinandan.one/x402-payments-overview-04a296ff/go-x402-register-payout.md) and the charge/pay flow in [Creating a Payment Challenge](https://test.abhinandan.one/x402-payments-overview-04a296ff/go-x402-create-charge.md); this page is only about the guardrail that sits in front of `Pay`.

## Read the current policy

`GetSpendPolicy` fetches the org's current policy over HTTP and returns the paused flag, both caps, and the allowlist.

### 1. Construct the x402 client

```go
package main

import (
	"context"
	"log"
	"os"

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

func main() {
	client := primitive.NewX402Client(primitive.X402ClientOptions{
		APIKey: os.Getenv("PRIMITIVE_API_KEY"),
	})

	ctx := context.Background()

	policy, err := client.GetSpendPolicy(ctx)
	if err != nil {
		log.Fatal(err)
	}
	log.Println(policy)
}
```

`NewX402Client` with zero options reads `PRIMITIVE_API_KEY` from the environment and targets the production host, same as any other x402 call.

### 2. Inspect the fields

The returned policy carries:

| Field | Meaning |
| --- | --- |
| `Paused` | Kill-switch. `true` refuses every outbound payment. |
| `MaxPerPayment` | Per-payment cap in token base units, or `nil` for no cap. |
| `MaxPerDay` | Daily cap in token base units, or `nil` for no cap. |
| `Allowlist` | Payee org ids allowed to receive payment. `nil` means any on-net payee; an empty slice denies all. |

USDC has 6 decimals, so a cap of `"5000000"` is 5.00 USDC.

## Update the policy

`SetSpendPolicy` merges: only the fields you set on the `X402SpendPolicyUpdate` change, and every field you omit keeps its current server-side value. Build the update with its setter methods, which chain.

### 1. Pause outbound payments (kill-switch)

```go
var update primitive.X402SpendPolicyUpdate
update.SetPaused(true)

policy, err := client.SetSpendPolicy(ctx, update)
if err != nil {
	log.Fatal(err)
}
log.Println("paused:", policy.Paused)
```

Nothing else on the policy changes: caps and the allowlist stay exactly as they were before this call.

### 2. Set a per-payment cap

```go
var update primitive.X402SpendPolicyUpdate
update.SetPaused(false).SetMaxPerPayment("5000000") // 5.00 USDC

policy, err := client.SetSpendPolicy(ctx, update)
if err != nil {
	log.Fatal(err)
}
```

Caps are token base units as decimal strings, the same convention as `Charge`'s `Amount` field. Chain setters to change several fields in one call.

### 3. Clear a cap

```go
var update primitive.X402SpendPolicyUpdate
update.ClearMaxPerPayment()
update.ClearMaxPerDay()

policy, err := client.SetSpendPolicy(ctx, update)
if err != nil {
	log.Fatal(err)
}
// policy.MaxPerPayment and policy.MaxPerDay are now nil (no cap).
```

Use `ClearMaxPerPayment` / `ClearMaxPerDay` to remove a cap. Because omitted fields keep their current value, there is no way to clear a cap by leaving it unset.

> **Warning:** `Paused: true` is the kill-switch: while it is set, every outbound payment is refused regardless of caps or allowlist. Flip it back with `update.SetPaused(false)` when you're ready to resume.

## List registered payout addresses

`ListPayoutAddresses` returns every payout address registered for the org, including which one is the default per network.

Spend policy governs outbound payment; the payout address directory is where inbound payment lands. List it alongside the policy when auditing an org's payment posture:

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

Registering a new payout address is covered in [Registering a Payout Address](https://test.abhinandan.one/x402-payments-overview-04a296ff/go-x402-register-payout.md).

## Errors

Every spend-policy method returns a `*primitive.X402Error` on a client-side, transport, or non-2xx server error; use `errors.As` to inspect it. Check `Status` (`0` means the request never reached the server), `Body` (the parsed error envelope), and `RetryAfter`. See [x402 Errors](https://test.abhinandan.one/x402-payments-overview-04a296ff/go-x402-errors.md) for the full error-handling reference.
