Documentation Index: Fetch llms.txt first to discover every published page. This page is also available as Markdown at /x402-payments-overview-04a296ff/python-x402-payout-and-policy.md.
Verified · 8/11/2026

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. For creating and settling challenges once a payout address exists, see Creating and Paying Challenges.

Register a payout address#

X402Client.register_payout_address is the Python entry point for x402 payout address registration: 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. 1

    Create the x402 client and signer#

    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. 2

    Register the address#

    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. 3

    Verify the address is registered#

    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 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(...).

FieldMeaning
pausedWhen True, all outbound payments are refused.
max_per_paymentCap in token base units, or None for no cap.
max_per_dayDaily cap in token base units, or None for no cap.
allowlistAllowed payee org ids. None means any on-net payee is allowed; [] denies all.
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.

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

Pass None explicitly for a field to clear that cap:

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:

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 for the full catalog.

Next steps#

Was this page helpful?

© Primitive SDKs

Powered by Browzer