Instant Payments

Accept Crypto Payments for Your Business

Fast, private, and production-ready payment infrastructure for merchants. Get paid in 147ms while protecting customer privacy.

Accept crypto payments 50x faster than traditional blockchain transactions with zero-knowledge privacy built-in.

Why ShadowPay for Merchants?

Accept payments on Solana with complete privacy. Traditional payments expose every transaction amount, sender, and recipient to the world. ShadowPay uses zero-knowledge proofs and ElGamal encryption to keep payment amounts private while maintaining instant settlement (147ms authorization, 5-15s on-chain). Your customers' purchase history stays confidential, and your revenue remains private.

Why ShadowPay?

Instant Payments (147ms)

Customers pay and receive instant access while settlement completes in the background.

Zero-Knowledge Privacy

Payment amounts encrypted with ElGamal. Customer identity and transaction details are private.

Production-Ready

Battle-tested infrastructure with PostgreSQL persistence, API key management, and comprehensive analytics.

Global & Permissionless

Accept payments from anyone, anywhere. No KYC, no chargebacks, no intermediaries. You own your revenue.

Quick Start (5 minutes)

Get your API protected and monetized in three simple steps

1

Get Your API Key

Create your merchant API key with a simple POST request. You'll need your Solana wallet address and a treasury wallet for receiving payments.

create-api-key.sh
curl -X POST https://shadow.radr.fun/shadowpay/v1/keys/new \
  -H "Content-Type: application/json" \
  -d '{
    "wallet_address": "YOUR_SOLANA_WALLET",
    "treasury_wallet": "YOUR_TREASURY_WALLET"
  }'
bash
Response:
{
  "api_key": "2hTKeADLwNZPeU5MeFcNKV4ttfWtpBUSEMiRVf4jRyjC",
  "rps_limit": 50,
  "daily_commit_limit": 10000,
  "wallet_address": "YOUR_SOLANA_WALLET",
  "treasury_wallet": "YOUR_TREASURY_WALLET"
}
json
2

Protect Your Endpoint

Add ShadowPay authentication to any endpoint. Return a 402 Payment Required response when no valid access token is present, or verify the token with ShadowPay's API.

server.js
const express = require('express');
const axios = require('axios');
const app = express();

// Your credentials
const MERCHANT_API_KEY = '2hTKeADLwNZPeU5MeFcNKV4ttfWtpBUSEMiRVf4jRyjC';
const MERCHANT_WALLET = 'YOUR_TREASURY_WALLET';
const ELGAMAL_SECRET_KEY = process.env.ELGAMAL_SECRET_KEY;

app.use(express.json());

app.get('/api/premium-data', async (req, res) => {
  const accessToken = req.headers['authorization']?.replace('Bearer ', '');
  
  // No token? Reject with 402 Payment Required
  if (!accessToken) {
    return res.status(402).json({
      error: 'Payment required',
      amount: 1000000, // 0.001 SOL in lamports
      merchant: MERCHANT_WALLET,
      message: 'Use ShadowPay SDK to authorize payment'
    });
  }
  
  // Verify token with ShadowPay (or verify JWT locally)
  try {
    const verify = await axios.get(
      `https://shadow.radr.fun/v1/payment/verify-access`,
      {
        headers: { 'Authorization': `Bearer ${accessToken}` }
      }
    );
    
    if (verify.data.valid) {
      // ✅ Payment authorized - return premium content
      return res.json({
        data: 'Your premium content here!',
        timestamp: Date.now(),
        message: 'Payment authorized, settlement in progress'
      });
    }
  } catch (error) {
    console.error('Token verification failed:', error.message);
  }
  
  // Invalid or expired token
  res.status(402).json({ error: 'Invalid or expired payment token' });
});

app.listen(3000, () => {
  console.log('✅ Protected API running on port 3000');
});
javascript
3

Frontend Integration

Use the ShadowPay JavaScript SDK to handle payments from your frontend. The SDK automatically generates ZK proofs in the background while users get instant access.

index.html
<!DOCTYPE html>
<html>
<head>
  <title>Premium Content</title>
  <script src="https://cdn.jsdelivr.net/npm/snarkjs@latest/build/snarkjs.min.js"></script>
  <script src="https://shadow.radr.fun/client/shadowpay-client.js"></script>
</head>
<body>
  <button onclick="unlockContent()">Unlock Premium Content (0.001 SOL)</button>
  <div id="content"></div>

  <script>
    const shadowpay = new ShadowPayClient({
      baseUrl: 'https://shadow.radr.fun'
    });

    async function unlockContent() {
      try {
        // Initialize SDK (load ZK circuits)
        await shadowpay.init();
        console.log('✅ ShadowPay SDK loaded');

        // Connect wallet (Phantom, Backpack, etc.)
        const wallet = window.solana;
        await wallet.connect();
        console.log('✅ Wallet connected:', wallet.publicKey.toString());

        // Make payment (instant authorization)
        const { accessToken, commitment, proofDeadline } = await shadowpay.pay({
          userWallet: wallet.publicKey.toString(),
          merchantWallet: 'YOUR_TREASURY_WALLET',
          merchantApiKey: 'YOUR_API_KEY',
          amount: 1000000, // 0.001 SOL
          onProofComplete: (result) => {
            if (result.success) {
              console.log('✅ Settlement complete:', result.tx_hash);
            } else {
              console.error('❌ Settlement failed:', result.error);
            }
          }
        });

        console.log('✅ Payment authorized! Token:', accessToken);
        console.log('⏳ Proof deadline:', new Date(proofDeadline * 1000));

        // Fetch premium content with access token
        const response = await fetch('http://localhost:3000/api/premium-data', {
          headers: { 'Authorization': `Bearer ${accessToken}` }
        });

        const data = await response.json();
        document.getElementById('content').innerHTML = `
          <h2>✅ Access Granted!</h2>
          <pre>${JSON.stringify(data, null, 2)}</pre>
        `;

      } catch (error) {
        console.error('❌ Payment failed:', error);
        alert('Payment failed: ' + error.message);
      }
    }
  </script>
</body>
</html>
html
4

Setup ZK Circuits (First Time Only)

Download and configure ZK circuit files for proof generation. The ShadowPay SDK needs these files to generate zero-knowledge proofs. This is a one-time setup that happens automatically, but you can also pre-load them.

setup-circuits.js
// Option 1: Automatic (Recommended)
// The SDK automatically downloads circuits on first init()
const shadowpay = new ShadowPayClient({
  baseUrl: 'https://shadow.radr.fun'
});

await shadowpay.init(); // Downloads and caches circuits
console.log('✅ Circuits loaded and cached in localStorage');

// Option 2: Manual Pre-loading (Advanced)
async function preloadCircuits() {
  const circuits = [
    {
      name: 'main-wasm',
      url: 'https://shadow.radr.fun/shadowpay/circuit/shadowpay_js/shadowpay.wasm',
      key: 'shadowpay_circuit_wasm'
    },
    {
      name: 'main-zkey',
      url: 'https://shadow.radr.fun/shadowpay/circuit/shadowpay_final.zkey',
      key: 'shadowpay_circuit_zkey'
    },
    {
      name: 'elgamal-wasm',
      url: 'https://shadow.radr.fun/shadowpay/circuit-elgamal/shadowpay-elgamal_js/shadowpay-elgamal.wasm',
      key: 'shadowpay_elgamal_wasm'
    },
    {
      name: 'elgamal-zkey',
      url: 'https://shadow.radr.fun/shadowpay/circuit-elgamal/shadowpay-elgamal_final.zkey',
      key: 'shadowpay_elgamal_zkey'
    }
  ];

  for (const circuit of circuits) {
    // Check if already cached
    if (localStorage.getItem(circuit.key)) {
      console.log(`${circuit.name} already cached`);
      continue;
    }

    console.log(`📥 Downloading ${circuit.name}...`);
    const response = await fetch(circuit.url);
    const buffer = await response.arrayBuffer();
    const base64 = btoa(String.fromCharCode(...new Uint8Array(buffer)));
    localStorage.setItem(circuit.key, base64);
    console.log(`✅ Cached ${circuit.name}`);
  }

  console.log('✅ All circuits cached successfully');
}

// Call this once during app initialization
await preloadCircuits();
javascript

Frontend ZK Proof Generation (Groth16)

Generate zero-knowledge proofs on the frontend using snarkjs and the downloaded circuit artifacts.

Setup & Dependencies

index.html
<!-- Include snarkjs library -->
<script src="https://cdn.jsdelivr.net/npm/snarkjs@latest/build/snarkjs.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/circomlibjs@latest/build/main.js"></script>

<!-- Or via npm -->
npm install snarkjs circomlibjs
html

Step 1: Prepare Witness Input

witness.js
import { buildPoseidon } from 'circomlibjs';

async function prepareWitnessInput(paymentData) {
  const poseidon = await buildPoseidon();
  
  // User's ShadowID commitment (from registration)
  const senderSecret = BigInt(localStorage.getItem('shadowid_secret'));
  const senderCommitment = poseidon.F.toString(poseidon([senderSecret]));
  
  // Get Merkle proof for sender
  const merkleProof = await fetch('https://shadow.radr.fun/shadowpay/api/shadowid/proof', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ commitment: senderCommitment })
  }).then(r => r.json());
  
  // Prepare witness input for circuit
  const witnessInput = {
    // Private inputs
    sender_commitment: senderCommitment,
    sender_secret: senderSecret.toString(),
    receiver_commitment: paymentData.merchantCommitment,
    amount: paymentData.amount.toString(), // lamports
    token_mint: "0", // 0 = SOL
    salt: generateRandomSalt(),
    merkle_path: merkleProof.proof.pathElements,
    path_indices: merkleProof.proof.pathIndices,
    
    // ElGamal encryption inputs
    encrypted_amount_c1: paymentData.elgamal.c1,
    encrypted_amount_c2: paymentData.elgamal.c2,
    elgamal_randomness: paymentData.elgamal.randomness,
    
    // Public inputs
    shadowid_root: merkleProof.proof.root,
    max_amount: (paymentData.amount * 2).toString(), // 2x buffer
    receiver_elgamal_pubkey: paymentData.merchantElGamalPubkey
  };
  
  return witnessInput;
}

function generateRandomSalt() {
  const randomBytes = new Uint8Array(32);
  crypto.getRandomValues(randomBytes);
  return BigInt('0x' + Array.from(randomBytes).map(b => b.toString(16).padStart(2, '0')).join(''));
}
javascript

Step 2: Generate Groth16 Proof

proof.js
async function generateGroth16Proof(witnessInput) {
  console.log('🔐 Generating Groth16 proof...');
  const startTime = Date.now();
  
  // Load circuit artifacts from cache (see Step 4 in Quick Start)
  const wasmB64 = localStorage.getItem('shadowpay_elgamal_wasm');
  const zkeyB64 = localStorage.getItem('shadowpay_elgamal_zkey');
  
  if (!wasmB64 || !zkeyB64) {
    throw new Error('Circuit artifacts not loaded. Run shadowpay.init() first.');
  }
  
  // Convert base64 to Uint8Array
  const wasmBytes = Uint8Array.from(atob(wasmB64), c => c.charCodeAt(0));
  const zkeyBytes = Uint8Array.from(atob(zkeyB64), c => c.charCodeAt(0));
  
  // Generate proof using snarkjs
  const { proof, publicSignals } = await snarkjs.groth16.fullProve(
    witnessInput,
    wasmBytes,
    zkeyBytes
  );
  
  const duration = Date.now() - startTime;
  console.log(`✅ Proof generated in ${duration}ms`);
  
  return {
    proof: {
      pi_a: proof.pi_a.slice(0, 2),
      pi_b: proof.pi_b.slice(0, 2).map(x => x.slice(0, 2)),
      pi_c: proof.pi_c.slice(0, 2),
      protocol: proof.protocol,
      curve: proof.curve
    },
    publicSignals: {
      shadowid_root: publicSignals[0],
      payment_commitment: publicSignals[1],
      payment_nullifier: publicSignals[2],
      encrypted_amount_commitment: publicSignals[3]
    },
    generationTime: duration
  };
}
javascript

Complete Payment Flow with ZK Proof

payment.js
async function makeZKPayment(merchantWallet, amount) {
  try {
    // 1. Encrypt amount with ElGamal (see ElGamal section)
    const elgamal = await encryptAmount(amount, merchantElGamalPubkey);
    
    // 2. Prepare witness input
    const witnessInput = await prepareWitnessInput({
      merchantCommitment: merchantWallet,
      merchantElGamalPubkey: merchantElGamalPubkey,
      amount: amount,
      elgamal: elgamal
    });
    
    // 3. Generate Groth16 proof
    const proofData = await generateGroth16Proof(witnessInput);
    
    // 4. Send to ShadowPay for verification and settlement
    const response = await fetch('https://shadow.radr.fun/shadowpay/settle', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        x402Version: 1,
        scheme: 'zkproof',
        network: 'solana-mainnet',
        proof: proofData.proof,
        publicSignals: proofData.publicSignals,
        encryptedAmount: {
          c1: elgamal.c1,
          c2: elgamal.c2
        },
        timestamp: Math.floor(Date.now() / 1000)
      })
    });
    
    const result = await response.json();
    
    if (result.success) {
      console.log('✅ Payment settled on-chain:', result.txHash);
      return {
        accessToken: result.accessToken,
        txHash: result.txHash,
        proofTime: proofData.generationTime
      };
    }
    
  } catch (error) {
    console.error('❌ Payment failed:', error);
    throw error;
  }
}
javascript

ElGamal Encryption (Frontend)

Encrypt payment amounts on the frontend using ElGamal encryption on the BN254 curve with Poseidon hash.

ElGamal Encryption Implementation

elgamal.js
import { buildPoseidon } from 'circomlibjs';

class ElGamalEncryptor {
  constructor() {
    this.poseidon = null;
  }
  
  async init() {
    this.poseidon = await buildPoseidon();
  }
  
  /**
   * Encrypt a payment amount using ElGamal
   * @param {number} amount - Amount in lamports
   * @param {string} recipientPublicKey - Merchant's ElGamal public key
   * @returns {object} - { c1, c2, randomness }
   */
  encryptAmount(amount, recipientPublicKey) {
    if (!this.poseidon) {
      throw new Error('ElGamal not initialized. Call init() first.');
    }
    
    // Generate random value r
    const randomBytes = new Uint8Array(32);
    crypto.getRandomValues(randomBytes);
    const randomness = BigInt('0x' + Array.from(randomBytes)
      .map(b => b.toString(16).padStart(2, '0'))
      .join('')
    );
    
    // c1 = g^r = Poseidon(r)
    const c1 = this.poseidon.F.toString(
      this.poseidon([randomness])
    );
    
    // c2 = h^r + m = Poseidon(pubkey, r) + amount
    const sharedSecret = this.poseidon.F.toString(
      this.poseidon([BigInt(recipientPublicKey), randomness])
    );
    const c2 = (BigInt(sharedSecret) + BigInt(amount)).toString();
    
    return {
      c1: c1,
      c2: c2,
      randomness: randomness.toString()
    };
  }
  
  /**
   * For merchants: Decrypt a payment amount with secret key
   * @param {string} c1 - ElGamal ciphertext component 1
   * @param {string} c2 - ElGamal ciphertext component 2
   * @param {string} secretKey - Merchant's ElGamal secret key
   * @returns {string} - Decrypted amount in lamports
   */
  decryptAmount(c1, c2, secretKey) {
    if (!this.poseidon) {
      throw new Error('ElGamal not initialized. Call init() first.');
    }
    
    // Reconstruct public key from secret key
    const publicKey = this.poseidon.F.toString(
      this.poseidon([BigInt(secretKey)])
    );
    
    // Decrypt: m = c2 - Poseidon(publicKey, c1)
    const sharedSecret = this.poseidon.F.toString(
      this.poseidon([BigInt(publicKey), BigInt(c1)])
    );
    
    let amount = BigInt(c2) - BigInt(sharedSecret);
    
    // Handle negative values (field arithmetic wrap-around)
    const FIELD_SIZE = 2n ** 254n;
    if (amount < 0n) {
      amount += FIELD_SIZE;
    }
    
    return amount.toString();
  }
}

// Usage example
const elgamal = new ElGamalEncryptor();
await elgamal.init();

// Encrypt payment amount
const encrypted = elgamal.encryptAmount(
  1000000, // 0.001 SOL in lamports
  merchantElGamalPubkey
);

console.log('Encrypted amount:', {
  c1: encrypted.c1,
  c2: encrypted.c2
  // randomness is kept secret, used in ZK proof
});

// For merchants: Decrypt received payment
const decrypted = elgamal.decryptAmount(
  encrypted.c1,
  encrypted.c2,
  merchantElGamalSecretKey
);

console.log('Decrypted amount:', decrypted, 'lamports');
javascript

Integration with Payment Flow

integration.js
async function integratedPaymentExample() {
  // Initialize ElGamal
  const elgamal = new ElGamalEncryptor();
  await elgamal.init();
  
  // Get merchant's ElGamal public key
  const merchantInfo = await fetch(
    `https://shadow.radr.fun/api/merchant/info/${merchantWallet}`
  ).then(r => r.json());
  
  const merchantElGamalPubkey = merchantInfo.elgamal_public_key;
  
  // Encrypt payment amount
  const amount = 1000000; // 0.001 SOL
  const encrypted = elgamal.encryptAmount(amount, merchantElGamalPubkey);
  
  console.log('📦 Encrypted payment amount');
  console.log('   c1:', encrypted.c1.substring(0, 20) + '...');
  console.log('   c2:', encrypted.c2.substring(0, 20) + '...');
  
  // Use encrypted amount in ZK proof generation
  const proofData = await generateGroth16Proof({
    // ... other witness inputs
    encrypted_amount_c1: encrypted.c1,
    encrypted_amount_c2: encrypted.c2,
    elgamal_randomness: encrypted.randomness,
    receiver_elgamal_pubkey: merchantElGamalPubkey
  });
  
  // Payment is now private - only merchant can decrypt the amount!
  return { encrypted, proofData };
}
javascript

Accept Payments For Anything

Private, instant crypto payments for merchants of all types

E-Commerce & Online Stores

Accept crypto payments for products and services

  • Digital goods
  • Physical products
  • Subscription services

Content Creators

Monetize your content with private payments

  • Premium articles
  • Exclusive videos
  • Digital downloads

SaaS & Software

Recurring payments for software and services

  • Monthly subscriptions
  • Usage-based billing
  • License keys

NFTs & Digital Assets

Private transactions for digital collectibles

  • NFT purchases
  • In-game items
  • Digital art

How Payment Works (Customer Experience)

1️⃣

Customer Initiates Payment

Customer selects product and clicks pay. Their wallet connects automatically (Phantom, Backpack, etc.).

2️⃣

Instant Authorization (147ms)

ShadowPay checks escrow balance and authorizes payment. Customer receives instant confirmation.

3️⃣

Immediate Delivery

Merchant receives notification and delivers product/service immediately. No waiting for blockchain confirmations.

4️⃣

Background Settlement (5-15s)

Zero-knowledge proof generated and settlement completes on-chain. Payment amount stays private with ElGamal encryption.

Total customer wait time: ~200ms ⚡

ShadowPay API Endpoints

Core API endpoints for payment integration

Merchant Setup

POST
/shadowpay/v1/keys/new

Create merchant API key

GET
/shadowpay/v1/keys/by-wallet/{wallet}

Get API key by wallet

Pool Management

GET
/shadowpay/api/pool/balance/{wallet}

Check user pool balance

POST
/shadowpay/api/pool/deposit

Deposit SOL to pool

POST
/shadowpay/api/pool/withdraw

Withdraw SOL from pool

Payment Flow

POST
/shadowpay/verify

Verify payment (instant check)

POST
/shadowpay/settle

Settle payment on-chain

GET
/v1/payment/verify-access

Verify access token

Merchant Analytics

GET
/v1/merchant/revenue

Track earnings (requires X-API-Key)

Circuit Artifacts Reference

Complete reference of all ZK circuit files. The SDK handles downloading automatically (see Quick Start Step 4), but these endpoints are available if you need manual access.

Main Circuit (Payment Proof)

GET
/shadowpay/circuit/shadowpay_final.zkey

Download proving key (main circuit)~50 MB

GET
/shadowpay/circuit/shadowpay_js/shadowpay.wasm

Download WASM (main circuit)~2 MB

ElGamal Circuit (Amount Encryption)

GET
/shadowpay/circuit-elgamal/shadowpay-elgamal_final.zkey

Download ElGamal proving key~45 MB

GET
/shadowpay/circuit-elgamal/shadowpay-elgamal_js/shadowpay-elgamal.wasm

Download ElGamal WASM~1.8 MB

Advanced: Manual Circuit Loading

setup-circuits.js
// For advanced use cases where you need direct circuit access
async function loadCircuitsManually() {
  const circuitWasm = await fetch(
    'https://shadow.radr.fun/shadowpay/circuit-elgamal/shadowpay-elgamal_js/shadowpay-elgamal.wasm'
  ).then(r => r.arrayBuffer());

  const provingKey = await fetch(
    'https://shadow.radr.fun/shadowpay/circuit-elgamal/shadowpay-elgamal_final.zkey'
  ).then(r => r.arrayBuffer());

  // Use with snarkjs for custom proof generation
  const { proof, publicSignals } = await snarkjs.groth16.fullProve(
    witnessInput,
    new Uint8Array(circuitWasm),
    new Uint8Array(provingKey)
  );
  
  return { proof, publicSignals };
}

// For most use cases, just use the SDK (see Quick Start Step 4)
const shadowpay = new ShadowPayClient({ baseUrl: 'https://shadow.radr.fun' });
await shadowpay.init(); // Handles everything automatically
javascript

💡 Most merchants should use the SDK's automatic download (Quick Start Step 4). Manual loading is only needed for custom ZK implementations.

Token Verification

Verify access tokens using JWT (recommended) or API calls

Option A: JWT Verification (Stateless)

jwt-verify.js
const jwt = require('jsonwebtoken');

app.get('/api/premium-data', async (req, res) => {
  const token = req.headers['authorization']?.replace('Bearer ', '');
  
  if (!token) {
    return res.status(402).json({ error: 'Payment required' });
  }
  
  try {
    const decoded = jwt.verify(token, process.env.SHADOWPAY_JWT_SECRET);
    
    if (decoded.exp < Math.floor(Date.now() / 1000)) {
      return res.status(402).json({ error: 'Token expired' });
    }
    
    return res.json({ data: 'Premium content!' });
  } catch (error) {
    return res.status(402).json({ error: 'Invalid token' });
  }
});
javascript

Option B: API Verification (Stateful)

api-verify.js
const axios = require('axios');

app.get('/api/premium-data', async (req, res) => {
  const token = req.headers['authorization']?.replace('Bearer ', '');
  
  if (!token) {
    return res.status(402).json({ error: 'Payment required' });
  }
  
  try {
    const verify = await axios.get(
      'https://shadow.radr.fun/v1/payment/verify-access',
      { headers: { 'Authorization': `Bearer ${token}` } }
    );
    
    if (verify.data.valid) {
      return res.json({ data: 'Premium content!' });
    }
    
    return res.status(402).json({ error: 'Payment not authorized' });
  } catch (error) {
    return res.status(402).json({ error: 'Verification failed' });
  }
});
javascript

Track Revenue

Check your earnings via the API:

curl https://shadow.radr.fun/v1/merchant/revenue \
  -H "X-API-Key: YOUR_API_KEY"
bash
Response:
{
  "total_revenue": "15450000",
  "total_payments": 1545,
  "recent_payments": [
    {
      "commitment": "14282575239580498641995859646780629054729399361619398221561866420322654695676",
      "amount": 1000000,
      "status": "settled",
      "timestamp": 1762764531
    }
  ]
}
json

Pricing & Economics

What You Pay:

  • Solana transaction fees: ~0.000005 SOL per settlement
  • ShadowPay fee: 0% (currently free during beta)

What You Charge:

  • Digital products: 0.01 - 10 SOL per item
  • Subscriptions: 0.1 - 100 SOL per month
  • NFTs & collectibles: 0.1 - 1000+ SOL
  • Services: Set your own pricing in SOL or SPL tokens

Webhook Notifications

Get notified when payments settle (optional)

webhooks.js
app.post('/webhooks/shadowpay', async (req, res) => {
  const { commitment, status, amount, tx_hash } = req.body;
  
  if (status === 'settled') {
    console.log(`✅ Payment settled: ${amount} lamports`);
    console.log(`TX: ${tx_hash}`);
    
    // Update database, grant access, etc.
  }
  
  res.sendStatus(200);
});
javascript

Security Best Practices

✅ DO:

  • Store API keys in environment variables
  • Use HTTPS for all API calls
  • Verify tokens on every request
  • Set reasonable amount limits
  • Log all transactions for auditing

❌ DON'T:

  • Expose API keys in client-side code
  • Trust client-provided amounts without verification
  • Skip token verification
  • Store sensitive data in access tokens

Traditional vs ShadowPay x402

See how ShadowPay compares to legacy HTTP 402 implementations

FeatureTraditional x402ShadowPay x402
Payment Speed5-10 seconds147ms
Customer ExperienceWait for confirmationsInstant delivery
PrivacyAll transactions publicAmounts encrypted
ChargebacksYes (high risk)None (final settlement)
Global AccessCountry restrictionsPermissionless
Settlement Time2-7 business days5-15 seconds

Frequently Asked Questions

Everything you need to know about integrating ShadowPay

Stay off the RADR.

Join the next generation of private payment infrastructure.

99.9%
Uptime
<200ms
Auth Speed
0
Fraud Cases