---
title: "Registering Payout Addresses and Spend Policy"
canonical: "https://test.abhinandan.one/x402-payments-overview-04a296ff/python-x402-payout-and-policy"
markdown_url: "https://test.abhinandan.one/x402-payments-overview-04a296ff/python-x402-payout-and-policy.md"
publisher: "Primitive SDKs"
kind: "guide"
content_type: "reference"
category: "Python SDK"
parent: "x402-payments-overview-04a296ff"
description: "register_payout_address signs an ownership message locally, then set_spend_policy configures caps and an allowlist to guard outbound x402 payments."
keywords: ["register_payout_address", "X402Client", "set_spend_policy", "get_spend_policy", "PrivateKeySigner", "list_payout_addresses"]
last_modified: "2026-08-11T18:55:05.012664+00:00"
published_at: "2026-08-11T18:55:04.863049+00:00"
source_files:
  - "sdk-python/src/primitive/x402/client.py"
  - "sdk-python/README.md"
  - "sdk-python/tests/test_x402_client.py"
sections:
  - {anchor: "register-a-payout-address", title: "Register a payout address"}
  - {anchor: "step-create-the-x402-client-and-signer", title: "Create the x402 client and signer"}
  - {anchor: "step-register-the-address", title: "Register the address"}
  - {anchor: "step-verify-the-address-is-registered", title: "Verify the address is registered"}
  - {anchor: "read-and-update-the-spend-policy", title: "Read and update the spend policy"}
  - {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

# Registering Payout Addresses and Spend Policy

Register a payee payout address with a proof-of-ownership signature so charge() can resolve pay_to, and configure the org's spend policy to cap and allowlist outbound x402 payments.

Every payee registers a payout address exactly once before it can receive x402 payments. Every org can also configure a spend policy that caps and allowlists the payments it sends. Do the first before your first `charge()`; do the second any time you want a kill-switch, per-payment/daily caps, or a payee allowlist on outbound payments.

For the full non-custodial payment model (four-step flow, amount formats, networks), see [x402 Payments Overview](https://test.abhinandan.one/x402-payments-overview.md). For creating and settling challenges once a payout address exists, see [Creating and Paying Challenges](https://test.abhinandan.one/x402-payments-overview-04a296ff/python-x402-charge-and-pay.md).

## Register a payout address

`X402Client.register_payout_address` is the Python entry point for [x402 payout address registration](https://test.abhinandan.one/x402-payments-overview.md): it proves control of a wallet with a local ownership signature and sets that address as your org's default payout destination for a network, so `charge()` can resolve `pay_to`.

### 1. Create the x402 client and signer

```python
import os
import primitive

x402 = primitive.create_x402_client(api_key=os.environ["PRIMITIVE_API_KEY"])
payee = primitive.PrivateKeySigner(os.environ["PAYEE_KEY"])
```

`PrivateKeySigner` holds the wallet key in process memory. The key is never sent to Primitive; it signs the ownership message locally.

### 2. Register the address

```python
result = x402.register_payout_address(
    signer=payee,
    network="base-sepolia",
    label="treasury",
)

print(result.is_default, result.address, result.verified_at)
```

`network` is `base-sepolia` (testnet) or `base` (mainnet). `label` is optional; it comes back on each entry from `list_payout_addresses`.

### 3. Verify the address is registered

```python
addresses = x402.list_payout_addresses()
print(addresses)
```

Expect at least one entry with `network="base-sepolia"` and `is_default=True`. This is the address `charge()` will fill in as `pay_to` for challenges you create on that network.

> **Tip:** Register once per network you plan to charge on. There's no per-charge payout address argument, `charge()` always resolves `pay_to` from your org's registered default for the challenge's `network`.

> **Warning:** `register_payout_address` requires a signer that supports the ownership-proof signature (`sign_message` under the hood). Passing a signer that can only do EIP-712 typed-data signing (the kind `pay()` needs) raises an `X402Error` naming the missing capability.

## Read and update the spend policy

The [spend policy](https://test.abhinandan.one/x402-payments-overview.md) guards every outbound x402 payment your org makes: a `paused` kill-switch, `max_per_payment` and `max_per_day` caps expressed in token base units (USDC has 6 decimals, so `"5000000"` is 5.00 USDC), and an `allowlist` of payee org ids. Read it with `x402.get_spend_policy()` and update it with `x402.set_spend_policy(...)`.

| Field | Meaning |
|---|---|
| `paused` | When `True`, all outbound payments are refused. |
| `max_per_payment` | Cap in token base units, or `None` for no cap. |
| `max_per_day` | Daily cap in token base units, or `None` for no cap. |
| `allowlist` | Allowed payee org ids. `None` means any on-net payee is allowed; `[]` denies all. |

```python
policy = x402.get_spend_policy()
print(policy.paused, policy.max_per_payment, policy.max_per_day, policy.allowlist)
```

`set_spend_policy` merges: only the fields you pass change, and omitted fields keep their current value.

```python
x402.set_spend_policy({"paused": False, "max_per_payment": "5000000"})
```

Pass `None` explicitly for a field to clear that cap:

```python
x402.set_spend_policy({"max_per_day": None})
```

> **Tip:** Use `paused: True` as an emergency stop for outbound payments without touching caps or the allowlist, a single-field update leaves everything else as-is.

## List registered payout addresses

`X402Client.list_payout_addresses` returns every payout address registered for your org, across all networks:

```python
for addr in x402.list_payout_addresses():
    print(addr.network, addr.address, addr.label, addr.is_default)
```

Each entry carries `id`, `address`, `network`, `label`, `is_default`, and `verified_at`.

## Errors

Every method on this page raises `primitive.X402Error` on a client-side, transport, or non-2xx server error. `register_payout_address`, `get_spend_policy`, `set_spend_policy`, and `list_payout_addresses` all raise `primitive.X402Error` on a client-side, transport, or non-2xx server error. `status` is the HTTP status, or `0` when the request never reached the server; `body` carries the parsed error envelope when present; `retry_after` carries the `Retry-After` header when the server sent one. See the [Python SDK Error Reference](https://test.abhinandan.one/python-errors-reference.md) for the full catalog.
