Menu

Explorer & Settings

Tempo Explorer Submit Project
🐹 Go guide

x402 in Go

x402 is plain HTTP 402, so adding USDC pay-per-request to a Go service takes only a handler and a facilitator call — no special framework required.

How do I use x402 in Go?

There is no official Go SDK yet, but x402 is just HTTP 402. On the server, check the request for an X-PAYMENT header in net/http (or middleware); if missing, respond 402 with an "accepts" body describing the price and your wallet, then verify payments by calling a facilitator's /verify endpoint. Clients follow the same 402-then-retry flow manually.

Which approach should you use?

Situation Use Why
One or two routesInline check in the handlerA few lines — no abstraction needed for a single gated endpoint.
Multiple gated routesrequirePayment middlewareWraps any handler with the same 402 check — write it once, reuse everywhere.
Building a facilitatorFull verify + settle serviceGo's concurrency model suits a service that verifies many on-chain payments per second.
Calling a paid endpointManual retry on 402No client package exists yet — handle the 402 → sign → retry loop yourself.

Server (net/http)

Return 402 with payment requirements until a valid X-PAYMENT header arrives, then serve.

// net/http handler that requires payment.
// x402 is just HTTP 402, so you can implement it directly in Go.
package main

import (
	"encoding/json"
	"net/http"
)

// Payment requirements returned on the 402 response.
var requirements = map[string]any{
	"scheme":    "exact",
	"network":   "base-sepolia", // use "base" in production
	"maxAmount": "10000",         // 0.01 USDC (6 decimals)
	"payTo":     "0xYourReceivingWalletAddress",
	"asset":     "USDC",
}

func weather(w http.ResponseWriter, r *http.Request) {
	payment := r.Header.Get("X-PAYMENT")
	if payment == "" || !verifyWithFacilitator(payment) {
		w.Header().Set("Content-Type", "application/json")
		w.WriteHeader(http.StatusPaymentRequired) // 402
		json.NewEncoder(w).Encode(map[string]any{"accepts": []any{requirements}})
		return
	}
	// Paid: serve the response
	json.NewEncoder(w).Encode(map[string]string{"city": "Tokyo", "forecast": "sunny"})
}

func main() {
	http.HandleFunc("/weather", weather)
	http.ListenAndServe(":8080", nil)
}

Verifying the payment

A facilitator checks the signed USDC payment on-chain so your server stays simple.

// Verify the payment by calling an x402 facilitator's
// /verify (and later /settle) endpoint over HTTP.
func verifyWithFacilitator(payment string) bool {
	// POST the X-PAYMENT payload + requirements to your facilitator,
	// which checks the signed USDC payment on-chain and returns valid=true.
	// Use a hosted facilitator or run your own — see the facilitators list.
	return callFacilitator("/verify", payment, requirements)
}

Middleware for multiple routes

Wrap any handler with the same check instead of repeating it.

// Reusable middleware instead of repeating the check in every handler.
func requirePayment(price string, next http.HandlerFunc) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		payment := r.Header.Get("X-PAYMENT")
		if payment == "" || !verifyWithFacilitator(payment) {
			w.Header().Set("Content-Type", "application/json")
			w.WriteHeader(http.StatusPaymentRequired)
			json.NewEncoder(w).Encode(map[string]any{"accepts": []any{requirements}})
			return
		}
		next(w, r)
	}
}

func main() {
	http.HandleFunc("/weather", requirePayment("$0.01", weather))
	http.ListenAndServe(":8080", nil)
}

Client (manual retry)

No official Go client package exists yet, so a caller reads the 402 body and retries with a signed payment itself.

// A Go client that pays automatically by handling the 402 itself.
// There's no official Go client SDK yet, so this shows the manual flow —
// most Go usage of x402 today is on the server/facilitator side.
resp, err := http.Get("http://localhost:8080/weather")
if err != nil {
	log.Fatal(err)
}
if resp.StatusCode == http.StatusPaymentRequired {
	var body struct{ Accepts []map[string]any `json:"accepts"` }
	json.NewDecoder(resp.Body).Decode(&body)
	// Sign a USDC payment for body.Accepts[0], then retry with
	// the X-PAYMENT header set to the signed payload.
	req, _ := http.NewRequest("GET", "http://localhost:8080/weather", nil)
	req.Header.Set("X-PAYMENT", signPayment(body.Accepts[0]))
	resp, _ = http.DefaultClient.Do(req)
}

Troubleshooting

Handler always returns 402, even after paying

Why: verifyWithFacilitator is checking the wrong field, or the facilitator call is failing silently and returning false by default.

Fix: Log the facilitator’s raw response once during development instead of swallowing errors into a plain bool.

"insufficient funds" on a testnet

Why: Your Base Sepolia test wallet has no faucet USDC (or no ETH for gas, depending on the facilitator’s settlement path).

Fix: Fund the address from a Base Sepolia USDC faucet before retrying — this never touches real money.

Amount charged looks 1,000,000x too big/small

Why: USDC uses 6 decimals. maxAmount must be an integer string in base units ("10000" = $0.01), not a dollar amount.

Fix: Use the free base-unit converter (linked below) to compute the integer.

X-PAYMENT header missing on the server

Why: A reverse proxy, load balancer or CDN in front of your Go service is stripping custom headers before they reach net/http.

Fix: Check the proxy config allows X-PAYMENT through, and log r.Header at the top of the handler to confirm what actually arrives.

Get amounts right with the free base-unit converter.

Go x402 projects

Real open-source implementations · stars live from GitHub.

NoFxAiOS/nofx

Your AI trading terminal assistant for US stocks, commodities, forex, and crypto.

⭐ 12.6k
gosuda/portal-tunnel

Publishes localhost services to the agentic web through self-hostable, trustless relays with x402 payments.

⭐ 264
solana-foundation/pay-kit

Building blocks for Agentic payments (x402, MPP, AP2) for TypeScript, Rust, Go, Python, Ruby, PHP, Lua, Kotlin and Swift.

⭐ 69
solana-foundation/mpp-sdk

Building blocks for Agentic payments (x402, MPP, AP2) for TypeScript, Rust, Go, Python, Ruby, PHP, Lua, Kotlin and Swift.

⭐ 69
mark3labs/x402-go

Go implementation of the x402 payment protocol

⭐ 31
Fewsats/proxy402

URL shortener

⭐ 26
Spritz-Labs/spritz

Spritz is a decentralized, permission-less and censorship resistant chat app for web3. Connect with friends using passkeys or wallets. Make HD video calls, go live to your followers, and chat freely on a decentralized network.

⭐ 20
deszhou/mpp-go

Go SDK for the Machine Payments Protocol

⭐ 19

Test for free on Base Sepolia, then use network: "base" in production. For other languages see the SDK guide, or the full tutorial.

Frequently asked questions

Is there a Go SDK for x402?

x402 is an open HTTP protocol, and there are community Go implementations including facilitator servers. There is no official Go client SDK yet, but because the protocol is plain HTTP 402, you can implement both server and client directly with net/http: return 402 with payment requirements, verify through a facilitator, then serve the response. The Go projects below are real, open-source starting points.

How do I gate a Go HTTP handler behind a payment?

On each request, check for the X-PAYMENT header. If it is missing or invalid, write HTTP 402 with an "accepts" list describing the price, network, asset (USDC) and your receiving address. If the payment verifies through a facilitator, run your normal handler. Wrap this in middleware (shown above) to apply it across routes instead of repeating the check.

What is a facilitator and do I need one in Go?

A facilitator is a service that verifies and settles the on-chain USDC payment so your server does not have to talk to the blockchain directly. Your Go code POSTs the payment payload to the facilitator’s /verify and /settle endpoints. You can use a hosted facilitator or self-host one — including Go-based facilitators.

How does a Go client pay an x402 endpoint?

There is no official Go client package yet, so a client handles the 402 manually: make the request, and if the response is 402, read the accepts array, sign a USDC payment for one of the listed requirements, then retry the request with the signed payload in the X-PAYMENT header.

Why use Go for x402?

Go’s net/http is a natural fit for lightweight facilitators and payment-gated APIs that need to handle high request volume with low overhead — no framework or SDK is strictly required since the protocol is just HTTP 402 plus a JSON body.

Can I test the Go x402 flow for free?

Yes. Point the network at "base-sepolia" and fund a test wallet from a free faucet. The 402 → pay → 200 flow is identical to mainnet; switch the network to "base" when you go live.

More: all SDKs · Python · Node.js · Rust