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

Creating a Payment Challenge (Go SDK)

Create an x402 payment challenge as the payee with Client.Charge, specifying the amount as human USDC or raw token base units, then hand the challenge to the payer.

Use Client.Charge when your agent is the payee and needs to request a USDC payment from another agent. It creates an x402 payment challenge that the payer signs and settles with Pay.

Before calling Charge, register a payout address once with RegisterPayoutAddress. Charge resolves pay_to from that registration, so a charge without one fails.

Note

This page covers the payee side (creating the challenge). The payer settles it with client.Pay(ctx, challenge, signer); for the shared payment model, see x402 Payments Overview. For a payment that rides a real email thread instead of a synthetic id, see the email-native flow on the same page.

Construct the x402 client#

Charge is a method on *primitive.X402Client, the x402 payments client built with NewX402Client; client construction and the shared payment model are explained in x402 Payments Overview. With zero options it reads PRIMITIVE_API_KEY from the environment and targets the production host (https://api.primitive.dev).

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"),
	})

	_, err := client.Charge(ctx, primitive.X402ChargeInput{
		AmountUsdc: "0.01",
		Network:    "base-sepolia",
	})
	if err != nil {
		log.Fatal(err)
	}
}

Create the challenge#

  1. 1

    Choose an amount format#

    Set exactly one of AmountUsdc (a human USDC decimal string like "0.01", the documented easy path) or Amount (token base units, e.g. "10000"); see x402 Payments Overview for how the two formats relate.

  2. 2

    Call Client.Charge#

    challenge, err := client.Charge(ctx, primitive.X402ChargeInput{
    	AmountUsdc:  "0.01", // human USDC amount
    	Network:     "base-sepolia",
    	PayerOrg:    os.Getenv("PAYER_ORG_ID"), // org allowed to pay
    	Description: "API call",
    })
    if err != nil {
    	log.Fatal(err)
    }
    

    Network is "base-sepolia" (testnet) or "base" (mainnet). PayerOrg binds the challenge to a specific paying org and is optional. Description is a free-text label surfaced back to the payer.

  3. 3

    Hand the challenge to the payer#

    challenge (a *X402Challenge) carries payment_requirements and nonce_binding, the exact fields the payer's Pay call signs over. Deliver it over any out-of-band channel (API response, dashboard, message).

Re-hydrate a challenge later#

GetChallenge re-hydrates an existing challenge by id, so you can retry Pay after a process restart without creating a duplicate:

challenge, err := client.GetChallenge(ctx, challengeID)
if err != nil {
	log.Fatal(err)
}
Tip

Need the challenge to ride a real email thread instead of a synthetic id? Use CreateEmailChallenge from the email-native flow described on x402 Payments Overview instead of Charge.

Warning

Setting both AmountUsdc and Amount on the same X402ChargeInput, or neither, is rejected before any network call is made. Set exactly one.

Errors#

Charge returns a *primitive.X402Error on any client-side, transport, or non-2xx server error, the shared x402 error shape described in x402 Payments Overview:

import (
	"errors"
	"log"

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

challenge, err := client.Charge(ctx, primitive.X402ChargeInput{Amount: "10000"})
if err != nil {
	var x402Err *primitive.X402Error
	if errors.As(err, &x402Err) {
		log.Printf("charge failed: status=%d retryAfter=%v", x402Err.Status, x402Err.RetryAfter)
	}
	return
}
_ = challenge

Common Charge-time rejections, all local (no network call made):

  • Malformed or missing amount: Amount must be a positive integer string; AmountUsdc must be a positive decimal with at most 6 decimal places.
  • Both Amount and AmountUsdc set, or neither set.

See x402 Errors for the full status-code reference, including retry-after handling and indeterminate-outcome cases.

Next steps#

Was this page helpful?

© Primitive SDKs

Powered by Browzer