Skip to content

NautilusOSS/x402-avm-client-server

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

2 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

x402 Basic Demo — AVM Payments on Voi

A minimal working example showing how to accept x402 crypto payments on Voi / Algorand using patterns from:

What is x402?

x402 is an open standard that brings the HTTP 402 Payment Required status code to life. A server responds with 402 when a resource requires payment, the client constructs and signs a blockchain transaction, then submits payment proof back to the server. Once verified, the server returns the protected resource.

This demo implements the simplest possible end-to-end flow:

Client → GET /premium/joke
       ← 402 Payment Required (price, receiver, note)
       → builds & signs VOI payment transaction
       → POST /premium/joke/pay { signedTxns }
       ← server verifies, submits, and confirms on-chain
       ← { joke: "..." }

Project Structure

server/
  src/
    index.ts                    Express server entry point
    routes/premium.ts           GET /premium/joke & POST /premium/joke/pay
    lib/paymentRequirement.ts   Payment requirement definition
    lib/verifyPayment.ts        Transaction decode, validate, submit & confirm

client/
  src/
    requestPremium.ts           Full client flow: request → pay → receive
    buildPaymentTxn.ts          Build native AVM payment transaction

Setup

npm install
cp .env.example .env

Edit .env:

  • SERVER_RECEIVER_ADDRESS — your Voi wallet address (receives payments)
  • CLIENT_MNEMONIC — 25-word mnemonic for the paying wallet (must hold VOI)

The defaults use Voi mainnet via the free Nodely endpoint.

Run

Start the server:

npm run server

In another terminal, run the client:

npm run client

Expected Output

Client:

→ Requesting GET /premium/joke ...
← 402 Payment Required — 0.01 VOI
→ Constructing payment transaction ...
→ Signing transaction ...
→ Submitting payment proof to POST /premium/joke/pay ...
← Payment verified! Response:
{
  "joke": "Why do blockchain developers hate nature? Too many forks."
}

Server:

x402-basic-demo server listening on http://localhost:3000
Payment verified — txId: ABC123...

How It Works

1. Client requests a premium resource

The client sends GET /premium/joke to the server. Instead of returning the joke, the server responds with HTTP 402 and a JSON body describing what payment is needed: amount, receiver address, network, and an ARC-2 formatted note identifying the resource.

2. Client builds and signs a payment transaction

Using algosdk, the client constructs a native VOI payment transaction with the exact receiver, amount (10,000 microunits = 0.01 VOI), and note from the 402 response. It then signs the transaction locally with the client's private key.

3. Client submits payment proof

The signed transaction is base64-encoded and sent back to POST /premium/joke/pay as { signedTxns: ["<base64>"] }.

4. Server verifies and submits the payment

The server's verification logic (verifyPayment.ts) follows the validation pattern from x402-avm-facilitator:

  1. Decode each signed transaction from base64 via algosdk.decodeSignedTransaction
  2. Check the genesis hash to confirm it targets the correct network (Voi mainnet)
  3. Find a matching pay transaction in the group with the right receiver, amount (\u2265 10,000 microunits), and note
  4. Submit the raw transaction to the Voi network via algod
  5. Wait for on-chain confirmation (up to 5 rounds)

5. Server returns the premium content

If the payment confirms on-chain, the server responds with the protected resource. If anything fails (wrong network, insufficient amount, submission error), it returns 400 with error details.

Trust model

The server never holds the client's keys. The client signs locally, but the server is the one that actually submits the transaction to the blockchain. The premium content is only released after on-chain confirmation — no trust required.

ARC-2 Note Format

Transaction notes use the ARC-2 structured format:

x402:j{"resource":"/premium/joke"}

The format is <dappName>:<formatChar><data> where j indicates JSON. This makes the payment's purpose machine-readable on-chain.

Payment Details

Field Value
Amount 0.01 VOI (10,000 microunits)
Asset VOI (native)
Network voi:mainnet
Note x402:j{"resource":"/premium/joke"}

Dependencies

  • algosdk — Algorand/Voi SDK for transaction construction & signing
  • express — HTTP server
  • dotenv — environment configuration
  • tsx — TypeScript execution

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors