---
title: "x402 Payments from the CLI"
canonical: "https://test.abhinandan.one/cli-overview/cli-payments"
markdown_url: "https://test.abhinandan.one/cli-overview/cli-payments.md"
publisher: "Primitive SDKs"
kind: "guide"
content_type: "reference"
category: "CLI"
parent: "cli-overview"
description: "Register a payout address, charge or pay an x402 USDC challenge, and manage spend policy from the terminal with the primitive payments-* CLI commands."
keywords: ["primitive payments register-payout-address", "primitive payments charge", "primitive payments pay-email", "primitive payments create-email-challenge", "PRIMITIVE_X402_PRIVATE_KEY", "primitive payments update-spend-policy"]
last_modified: "2026-08-21T18:22:43.359885+00:00"
published_at: "2026-08-11T18:54:54.948031+00:00"
sections:
  - {anchor: "set-your-wallet-key", title: "Set your wallet key"}
  - {anchor: "register-a-payout-address-payee-one-time", title: "Register a payout address (payee, one time)"}
  - {anchor: "step-export-your-wallet-key", title: "Export your wallet key"}
  - {anchor: "step-register-the-address", title: "Register the address"}
  - {anchor: "create-a-payment-challenge-payee", title: "Create a payment challenge (payee)"}
  - {anchor: "pay-a-challenge-payer", title: "Pay a challenge (payer)"}
  - {anchor: "inspect-a-challenge-or-your-payout-addresses", title: "Inspect a challenge or your payout addresses"}
  - {anchor: "email-native-payments", title: "Email-native payments"}
  - {anchor: "step-payee-issue-the-challenge-over-email", title: "Payee: issue the challenge over email"}
  - {anchor: "step-payer-sign-and-send-in-one-step", title: "Payer: sign and send in one step"}
  - {anchor: "read-and-update-the-spend-policy", title: "Read and update the spend policy"}
  - {anchor: "next-steps", title: "Next steps"}
---

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

# x402 Payments from the CLI

Register a payout address, create and pay x402 USDC challenges (including the email-native flow), and inspect settlements and spend policy directly from the terminal with the primitive payments command group.

The `primitive payments` command group drives the same non-custodial [x402 payment model](https://test.abhinandan.one/x402-payments-overview.md) as the SDKs, from your shell. Reach for it when you want to register a payout address, request or settle a USDC payment, or inspect settlements and spend policy without writing code, for example scripting a payment into CI, or testing a payment flow before wiring it into a Function.

One agent registers a payout address and requests a payment with `charge`; the paying agent signs locally with its own wallet key and settles with `pay`. The signing key never leaves your machine, it is read from an environment variable or flag and used only to sign locally. Networks are `base` (mainnet) and `base-sepolia` (testnet); amounts take either a human USDC value (`--amount-usdc 0.01`) or token base units (`--amount 10000`, since USDC has 6 decimals). Your org is resolved automatically from your API key, so payout registration takes no org flag.

> **Note:** This page assumes you already have the CLI installed and authenticated. See [What is the Primitive CLI?](https://test.abhinandan.one/cli-overview.md) and [Authentication: login, signup, logout, whoami](https://test.abhinandan.one/cli-overview/cli-authentication.md) if you haven't set that up yet.

## Set your wallet key

The signing commands (`register-payout-address`, `pay`, `pay-email`, `pay-email-step`) need a wallet private key to sign locally. Set it as an environment variable so it never lands in shell history or the process list:

```bash
export PRIMITIVE_X402_PRIVATE_KEY=0x...
```

A `--private-key` flag exists as an escape hatch for scripted use, but the environment variable is preferred.

The non-signing commands (`charge`, `get-challenge`, `list-payout-addresses`, `get-spend-policy`, `update-spend-policy`) need only your Primitive API key (set via `primitive login` or `PRIMITIVE_API_KEY`); they don't touch the wallet key at all.

## Register a payout address (payee, one time)

Do this once per org before you ever call `charge`. It signs an ownership message locally with your wallet key and proves control of the address; the recovered address becomes your org's default payout destination for that network.

### 1. Export your wallet key

```bash
export PRIMITIVE_X402_PRIVATE_KEY=0x...
```

### 2. Register the address

```bash
primitive payments register-payout-address --network base-sepolia --label treasury
```

The command prints a human-readable summary by default. Pass `--json` for the raw registration object.

> **Tip:** Your org id is resolved automatically from your API key, payout registration takes no `--org` flag.

## Create a payment challenge (payee)

`charge` creates an [x402 payment challenge](https://test.abhinandan.one/x402-payments-overview.md) with a human USDC amount and prints the challenge JSON to stdout, with a one-line summary on stderr:

```bash
primitive payments charge --network base-sepolia --amount-usdc 0.01
```

Capture the challenge JSON to hand to the payer:

```bash
primitive payments charge --network base-sepolia --amount-usdc 0.01 > challenge.json
```

`charge` is the friendly verb that matches the SDKs' `charge()` / `Charge()` and accepts `--amount-usdc`. The lower-level `create-challenge` command takes base-unit `--amount` instead; either creates a challenge.

## Pay a challenge (payer)

`pay` signs and settles the challenge locally, using your wallet key. It reads the challenge inline, from a file, or piped on stdin:

```bash
primitive payments pay --challenge-file challenge.json
```

```bash
cat challenge.json | primitive payments pay
```

`pay` prints a human-readable summary by default, and raw JSON with `--json`.

> **Warning:** `pay` needs `PRIMITIVE_X402_PRIVATE_KEY` (or `--private-key`) set to your wallet's private key. Anyone with that key can sign payments from your address, keep it out of shell history and CI logs.

## Inspect a challenge or your payout addresses

Look up a challenge by id, or list every payout address registered for your org:

```bash
primitive payments get-challenge --id <challenge-id>
primitive payments list-payout-addresses
```

## Email-native payments

The [email-native x402 payment](https://test.abhinandan.one/x402-payments-overview.md) flow rides a real email thread instead of an out-of-band challenge id. The payee issues the challenge as an email; the payer signs it into an `interaction.json` payment step and sends it back.

### 1. Payee: issue the challenge over email

`create-email-challenge` takes `--amount` in token base units only, unlike `charge` it has no `--amount-usdc`. USDC has 6 decimals, so multiply by 1,000,000: 0.01 USDC is `--amount 10000`.

```bash
primitive payments create-email-challenge --from payee@your-domain.example \
  --to payer@their-domain.example --amount 10000 --network base-sepolia
```

### 2. Payer: sign and send in one step

`pay-email` is the recommended payer path: it signs the challenge locally with your wallet key AND sends the signed `interaction.json` attachment, so you skip the manual sign-then-send dance. `--in-reply-to` is the inbound challenge email you received; it's fetched to address the payment to the payee, with `From` defaulting to the address the challenge was sent to. The send is not threaded under the challenge itself, the payment associates by `interaction_id` instead.

```bash
primitive payments pay-email --challenge-file challenge.json \
  --in-reply-to <inbound-challenge-email-id> --wait
```

The message carries a short default note alongside the attachment; pass `--body` to customize it.

For advanced cases where you need to deliver the signed envelope yourself (for example attaching it with `primitive send --attachment`), sign only without sending:

```bash
primitive payments pay-email-step --challenge-file challenge.json > interaction.json
```

> **Tip:** All four signing commands (`register-payout-address`, `pay`, `pay-email`, `pay-email-step`) accept `--json`. `pay-email` and `pay-email-step` print JSON by default (the send result and the `interaction.json` bytes, respectively); `--json` switches them to a fuller envelope object.

## Read and update the spend policy

The [spend policy](https://test.abhinandan.one/x402-payments-overview.md) guards outbound payments with a kill-switch, per-payment and daily caps in token base units, and a payee allowlist. Read the current policy, or update it, the update merges, so omitted fields keep their current value:

```bash
primitive payments get-spend-policy
primitive payments update-spend-policy --max-per-payment 5000000
```

For the full flag list of any command, run:

```bash
primitive payments <command> --help
```
