Go SDK
Gate any HTTP route for stablecoin payments with the pay-kit Go module — one paykit umbrella, net/http middleware that advertises both MPP and x402.
The pay-kit Go module (github.com/solana-foundation/pay-kit/go) is stablecoin payment gating for HTTP services. Pick a currency, give it your wallet address, and gate a net/http route — an unpaid request gets a 402 Payment Required advertising both x402 and MPP, and the client settles with either. You do not need to know anything about Solana to use it.
Install
go get github.com/solana-foundation/pay-kit/goThe paykit umbrella is the surface; blank-importing the two protocol adapters (and a signer) registers them, so one gate advertises both protocols at once.
Quick start
Create the client
paykit.New takes a Config: the network, the protocols you Accept, and an MPP realm + challenge-binding secret. With no Operator.Signer it boots on the in-memory demo signer and the Surfpool sandbox — enough to run locally.
import (
"fmt"
"net/http"
"github.com/solana-foundation/pay-kit/go/paykit"
_ "github.com/solana-foundation/pay-kit/go/paycore/signer"
_ "github.com/solana-foundation/pay-kit/go/paykit/adapters/mpp"
_ "github.com/solana-foundation/pay-kit/go/paykit/adapters/x402"
)client, err := paykit.New(paykit.Config{ Network: paykit.SolanaLocalnet, Accept: []paykit.Protocol{paykit.X402, paykit.MPP}, MPP: paykit.MPPConfig{ Realm: "MyApp", ChallengeBindingSecret: []byte("local-dev-secret"), },})if err != nil { panic(err)}gate := paykit.Gate{Amount: paykit.MustParseUSD("0.01"), Desc: "Stock quote"}// client.Require(gate) is func(http.Handler) http.Handler — it settles the// 402 (MPP or x402, the client's choice) before your handler runs.mux := http.NewServeMux()mux.Handle("/quote", client.Require(gate)(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { pmt, _ := paykit.PaymentFrom(r.Context()) fmt.Fprintf(w, `{"ok":true,"paid_via":%q}`, pmt.Protocol)})))Gate your routes
client.Require(gate) is a plain func(http.Handler) http.Handler, so it composes with chi, gorilla, or the stdlib mux. It settles the 402 before your handler runs; inside the handler, paykit.PaymentFrom(r.Context()) returns the verified payment.
Run it
go run .Make a paid call
Hit the route with the pay CLI — it walks the user through approval and pays in USDC:
pay curl http://127.0.0.1:4567/quoteGo also ships the paying side. x402client.NewClient returns an *http.Client whose transport settles a 402 in one retry, then replays the request with the credential — so any *http.Client call pays transparently:
import x402client "github.com/solana-foundation/pay-kit/go/protocols/x402/client"// The returned *http.Client settles a 402 transparently on any call.httpClient := x402client.NewClient(signer, rpc)resp, err := httpClient.Get("https://api.example.com/quote")if err != nil { panic(err)}defer resp.Body.Close()body, _ := io.ReadAll(resp.Body)fmt.Println(string(body))The sibling protocols/mpp/client does the same for MPP. See Client.
No Go at all — the pay CLI is a client for any 402-gated route, handling wallet, signing, and the payment retry for you:
brew install pay # or: npm install -g @solana/pay
pay --sandbox curl https://debugger.pay.sh/mpp/quote/AAPLNext steps
- Payment schemes — fixed charge and metered usage (
upto). - Pricing — amounts, settlement assets, fees, and splits.
- Client — the paying side.
- Signers — local keys and fee sponsorship.
- Errors — the error values and the boot-time safety rails.