Skip to content

Payment Concepts

Learn about x402 payment concepts and how they work within your n8n workflows.

An x402 payment is a cryptographically signed proof that demonstrates:

  • The payer’s wallet address
  • The exact amount being paid
  • The token/asset used (USDC)
  • When the payment was created
  • That the payer owns the wallet (via signature)
{
"x402Version": 1,
"scheme": "exact",
"network": "solana-devnet",
"payload": {
"signature": "5YGc9Lcqv3Nvx...",
"from": "9rKnvE7PVbpq4Ws...",
"amount": "10000",
"mint": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU",
"timestamp": 1705318200
}
}

x402Version: Protocol version (always 1)

scheme: Payment method

  • exact = Pay exact amount specified
  • Future: range, subscription, etc.

network: Blockchain network

  • solana-devnet = Solana Devnet (testing)
  • solana-mainnet = Solana Mainnet (production)

payload.signature: Cryptographic signature

  • Base58 encoded
  • 64 bytes
  • Proves wallet ownership
  • Created by signing message with private key

payload.from: Payer’s wallet address

  • Public key in base58
  • Visible on blockchain
  • Used to verify signature

payload.amount: Payment amount in smallest units

  • 10000 = 0.01 USDC (6 decimals)
  • 100000 = 0.10 USDC
  • 1000000 = 1.00 USDC

payload.mint: Token/asset address

  • USDC mint address on Solana
  • Devnet: 4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU
  • Mainnet: EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v

payload.timestamp: Unix timestamp

  • When payment was created
  • Used for replay protection
  • Must be recent (< 5 minutes)
{
"x402Version": 1,
"accepts": [
{
"scheme": "exact",
"maxAmountRequired": "10000",
"payTo": "ABC123...",
"asset": "4zMMC9srt5...",
"network": "solana-devnet"
}
]
}
const requirements = response.accepts[0];
const amount = requirements.maxAmountRequired; // "10000"
const recipient = requirements.payTo; // "ABC123..."
const mint = requirements.asset; // "4zMMC9srt5..."
const network = requirements.network; // "solana-devnet"
const timestamp = Math.floor(Date.now() / 1000);
const message = {
from: walletAddress, // "9rKnvE7..."
amount: amount, // "10000"
mint: mint, // "4zMMC9srt5..."
timestamp: timestamp, // 1705318200
};
const messageJson = JSON.stringify(message);
const messageBytes = encode(messageJson);
const signatureBytes = sign(messageBytes, privateKey);
const signature = base58Encode(signatureBytes);
const payload = {
x402Version: 1,
scheme: "exact",
network: network,
payload: {
signature: signature,
...message,
},
};
const json = JSON.stringify(payload);
const base64 = btoa(json);
// Result: "eyJ4NDAyVmVyc2lvbiI6MSw..."
GET /api/premium-data HTTP/1.1
Host: api.example.com
X-Payment: eyJ4NDAyVmVyc2lvbiI6MSw...

All of this happens automatically in the x402 Client node!

  1. Payload Structure: Valid JSON with required fields
  2. Protocol Version: Must be version 1
  3. Scheme: Must be “exact” (currently)
  4. Network: Must match server’s network
  5. Amount: Must match exactly
  6. Mint/Asset: Must be USDC
  7. Timestamp: Must be recent (< 5 minutes)
  8. Signature: Must be valid for the message and wallet
  9. Duplicate: Must not have been used before
1. Decode base64 header
↓
2. Parse JSON
↓
3. Check structure
↓
4. Verify amount matches
↓
5. Verify network matches
↓
6. Verify asset is USDC
↓
7. Check timestamp age
↓
8. Verify signature format
↓
9. Check not duplicate
↓
10. Accept or reject

USDC has 6 decimal places:

Smallest Units → USDC
10000 → 0.01
100000 → 0.10
1000000 → 1.00
10000000 → 10.00
// Smallest units to USDC
const usdc = smallestUnits / 1_000_000;
// USDC to smallest units
const smallestUnits = usdc * 1_000_000;
0.01 USDC = 10,000 smallest units
0.05 USDC = 50,000 smallest units
0.10 USDC = 100,000 smallest units
1.00 USDC = 1,000,000 smallest units

The x402 Client handles this conversion automatically.

Signatures prove wallet ownership without revealing private keys:

Private Key (secret)
→ Signs message
→ Produces signature (public)
Server verifies:
Message + Signature + Public Key = Valid? ✓

Prevents reusing the same payment:

Timestamp Check:

  • Payments older than 5 minutes are rejected
  • Prevents old payments from being replayed

Signature Tracking:

  • Servers track used signatures
  • Duplicate signatures are rejected
  • Even within the time window

Exact Match Required:

  • Cannot pay less than required
  • Cannot pay more and get credit
  • Must pay exactly the specified amount

Client-Side Limit:

  • Max payment amount configured in node
  • Prevents accidental overspending
  • Workflow fails instead of overpaying

Devnet vs Mainnet:

  • Payments on devnet don’t work on mainnet
  • Prevents accidental real money in testing
  • Wallets are network-specific

The only currently implemented scheme:

{
"scheme": "exact",
"maxAmountRequired": "10000"
}

Characteristics:

  • Pay exactly the specified amount
  • No partial payments
  • No overpayment credit
  • Simple and predictable

The x402 protocol supports future extensions:

Range Scheme:

{
"scheme": "range",
"minAmountRequired": "10000",
"maxAmountRequired": "50000"
}

Pay any amount in range.

Subscription Scheme:

{
"scheme": "subscription",
"amountRequired": "1000000",
"validityPeriod": 2592000
}

Pay once for time-based access.

Invoice Scheme:

{
"scheme": "invoice",
"items": [
{ "resource": "/api/a", "amount": "10000" },
{ "resource": "/api/b", "amount": "20000" }
]
}

Pay for multiple items at once.

x402 Client creates payment when 402 is received.

Triggers: 402 response from API

Duration: ~10-20ms

Payment sent in X-Payment header.

Triggers: Automatic retry by Client

Duration: Network latency (~100-500ms)

Server verifies payment proof.

Triggers: Server receives request with X-Payment

Duration: ~5-15ms

Server marks signature as used.

Triggers: After successful verification

Duration: < 1ms

Server returns protected data.

Triggers: After payment acceptance

Duration: Depends on API processing

  1. Set reasonable limits: Don’t set max too high
  2. Monitor balances: Check wallet regularly
  3. Use devnet first: Test before production
  4. Log payments: Track spending for budgeting
  5. Handle errors: Implement error handling
  1. Clear pricing: Document exact costs
  2. Stable prices: Don’t change frequently
  3. Fast verification: Keep latency low
  4. Good errors: Clear rejection reasons
  5. Track payments: Audit trail for compliance

The Client node includes payment metadata in output:

{
"_x402Payment": {
"amount": "0.01", // For logging
"currency": "USDC", // For display
"recipient": "ABC123...", // Where it went
"sender": "9rKnvE7...", // Who paid
"network": "solana-devnet", // Which blockchain
"timestamp": "2024-01-15T10:30:00.000Z" // When
}
}

Log to database or file:

// In Code node after Client
const log = {
workflow: $workflow.name,
execution: $execution.id,
timestamp: new Date().toISOString(),
apiUrl: "{{$node['x402 Client'].parameter.resourceUrl}}",
paymentAmount: $json._x402Payment?.amount || "0",
success: $json._x402Payment !== undefined,
};
// Send to logging service
return { json: log };
API Call Cost: 0.01 USDC
Blockchain Fee: ~0.000005 SOL (~$0.0005)
Total: ~$0.01 + $0.0005 = ~$0.0105
1 call/hour = 720 calls/month = ~$7.20
1 call/day = 30 calls/month = ~$0.30
1 call/week = 4 calls/month = ~$0.04

Calculate expected costs:

const callsPerDay = 24; // Hourly workflow
const costPerCall = 0.01; // 0.01 USDC per call
const daysPerMonth = 30;
const monthlyCost = callsPerDay * costPerCall * daysPerMonth;
// Result: $7.20/month
const recommendedBalance = monthlyCost * 1.2; // 20% buffer
// Fund wallet with: $8.64