# Integration Code

```bash
# Install dependencies
npm install @numpay/zk-sdk @numpay/core snarkjs ethers

# Or for Python
pip install numpay-zk-sdk numpay-core snarkjs-py web3
```

### Step 1: Initialize NumPay ZK Client

```typescript
// client/numpayZKClient.ts
import { NumPayZKClient } from '@numpay/zk-sdk';
import { NumPayCore } from '@numpay/core';

class NumPayPrivateClient {
  private zkClient: NumPayZKClient;
  private numpay: NumPayCore;

  constructor(privateKey?: string, phone?: string) {
    // Initialize NumPay core with phone linking
    this.numpay = new NumPayCore({
      privateKey: privateKey,
      phoneNumber: phone,
      encryptIdentity: true, // Enable encrypted phone mapping
      network: 'mainnet'
    });

    // Initialize ZK client
    this.zkClient = new NumPayZKClient({
      circuitUrl: 'https://api.numpay.io/zk/circuits',
      provingKeyUrl: 'https://api.numpay.io/zk/proving-key',
      verificationKeyUrl: 'https://api.numpay.io/zk/verification-key'
    });
  }

  async initialize() {
    console.log('Loading ZK circuit artifacts...');
    await this.zkClient.loadCircuits();
    console.log('ZK client ready!');

    // Link phone to wallet if provided
    if (this.numpay.phoneNumber) {
      await this.numpay.linkPhoneToWallet();
    }
  }

  async getWalletAddress(): Promise<string> {
    return await this.numpay.getAddress();
  }

  async resolvePhoneToWallet(phone: string): Promise<string> {
    // Resolve phone using NumPay's encrypted mapping
    return await this.numpay.identity.resolvePhone(phone);
  }
}

export default NumPayPrivateClient;

```

### Step 2: Generate Private Payment Proof

```typescript
// client/generateProof.ts
import NumPayPrivateClient from './numpayZKClient';

interface PaymentProof {
  proof: string[];
  publicSignals: string[];
  encryptedAmount: string;
  amountProof: string[];
  senderCommitment: string;
  recipientPublicKey: string;
}

async function generatePrivatePayment(
  senderPhone: string,
  recipientPhone: string,
  amount: number,
  resourceUrl: string
): Promise<PaymentProof> {

  // Initialize client
  const client = new NumPayPrivateClient(
    process.env.PRIVATE_KEY,
    senderPhone
  );
  await client.initialize();

  // Resolve recipient phone to wallet (encrypted)
  const recipientWallet = await client.resolvePhoneToWallet(recipientPhone);
  const senderWallet = await client.getWalletAddress();

  console.log('Generating ZK proof for payment...');
  console.log(`From: ${senderPhone} (hidden)`);
  console.log(`To: ${recipientPhone}`);
  console.log(`Amount: ${amount} (will be encrypted)`);

  // Generate zero-knowledge proof
  const proof = await client.zkClient.generatePaymentProof({
    senderAddress: senderWallet,
    recipientAddress: recipientWallet,
    amount: amount,
    resourceUrl: resourceUrl,

    // Privacy options
    hideAmount: true,          // Encrypt amount with ElGamal
    hideSender: true,          // Use ZK proof for sender privacy
    usePhoneMapping: true,     // Enable phone-based addressing

    // Additional metadata (encrypted)
    metadata: {
      timestamp: Date.now(),
      paymentReason: 'x402 API access',
      encryptMetadata: true
    }
  });

  console.log('✓ ZK proof generated!');

  return {
    proof: proof.proof,
    publicSignals: proof.publicSignals,
    encryptedAmount: proof.encryptedAmount,
    amountProof: proof.amountRangeProof,
    senderCommitment: proof.senderCommitment,
    recipientPublicKey: recipientWallet
  };
}

export { generatePrivatePayment, PaymentProof };

```

### Step 3: Implement x402 Middleware with ZK Verification

```typescript
// server/x402ZKMiddleware.ts
import express from 'express';
import { NumPayZKVerifier } from '@numpay/zk-sdk';
import { NumPayCore } from '@numpay/core';

class X402ZKMiddleware {
  private verifier: NumPayZKVerifier;
  private numpay: NumPayCore;
  private merchantPhone: string;
  private pricePerRequest: number;

  constructor(config: {
    merchantPhone: string;
    merchantWallet: string;
    pricePerRequest: number;
  }) {
    this.merchantPhone = config.merchantPhone;
    this.pricePerRequest = config.pricePerRequest;

    // Initialize NumPay with merchant credentials
    this.numpay = new NumPayCore({
      walletAddress: config.merchantWallet,
      phoneNumber: config.merchantPhone,
      encryptIdentity: true
    });

    // Initialize ZK verifier
    this.verifier = new NumPayZKVerifier({
      verificationKeyUrl: 'https://api.numpay.io/zk/verification-key'
    });
  }

  async middleware(
    req: express.Request,
    res: express.Response,
    next: express.NextFunction
  ) {
    // Check for payment proof header
    const paymentProofHeader = req.headers['x-payment-proof'];

    if (!paymentProofHeader) {
      return this.sendPaymentRequired(req, res);
    }

    try {
      // Parse and verify ZK proof
      const proofData = JSON.parse(paymentProofHeader as string);
      const isValid = await this.verifyZKProof(proofData);

      if (!isValid) {
        return res.status(402).json({
          error: 'Invalid payment proof',
          message: 'ZK proof verification failed'
        });
      }

      // Proof valid - proceed to resource
      req.paymentProof = proofData; // Attach proof to request
      next();

    } catch (error) {
      return res.status(400).json({
        error: 'Invalid payment proof format',
        message: error.message
      });
    }
  }

  private async sendPaymentRequired(
    req: express.Request,
    res: express.Response
  ) {
    const merchantWallet = await this.numpay.getAddress();

    const paymentInstructions = {
      status: 402,
      message: 'Payment Required',
      protocol: 'x402',
      privacy: 'zero-knowledge',

      payment: {
        method: 'numpay-zk',
        recipient: {
          phone: this.merchantPhone,     // Users can pay to phone!
          wallet: merchantWallet,         // Or wallet address
          encryptedMapping: true          // Phone mapping is encrypted
        },
        amount: this.pricePerRequest,
        currency: 'USDC',

        // Privacy features
        privacy: {
          amountEncryption: 'elgamal',
          senderPrivacy: 'zero-knowledge',
          proofSystem: 'groth16'
        },

        // ZK proof requirements
        zkProof: {
          required: true,
          circuitUrl: 'https://api.numpay.io/zk/circuits',
          provingKeyUrl: 'https://api.numpay.io/zk/proving-key',
          expectedPublicInputs: [
            'recipientAddress',
            'resourceUrl',
            'encryptedAmount'
          ]
        },

        // Verification endpoint
        verifyEndpoint: 'https://api.numpay.io/zk/verify',
        settleEndpoint: 'https://api.numpay.io/zk/settle'
      },

      metadata: {
        requestId: this.generateRequestId(),
        timestamp: Date.now(),
        resource: req.originalUrl
      }
    };

    res.status(402)
       .set('WWW-Authenticate', 'x402-zk')
       .json(paymentInstructions);
  }

  private async verifyZKProof(proofData: any): Promise<boolean> {
    try {
      // Step 1: Verify ZK proof structure and cryptography
      const proofValid = await this.verifier.verify({
        proof: proofData.proof,
        publicSignals: proofData.publicSignals
      });

      if (!proofValid) {
        console.error('ZK proof verification failed');
        return false;
      }

      // Step 2: Verify encrypted amount proof
      const amountProofValid = await this.verifier.verifyAmountProof({
        encryptedAmount: proofData.encryptedAmount,
        amountProof: proofData.amountProof,
        minAmount: this.pricePerRequest,
        maxAmount: this.pricePerRequest * 1.1 // 10% tolerance
      });

      if (!amountProofValid) {
        console.error('Amount proof verification failed');
        return false;
      }

      // Step 3: Verify recipient is correct (without decrypting)
      const merchantWallet = await this.numpay.getAddress();
      const recipientValid = proofData.recipientPublicKey === merchantWallet;

      if (!recipientValid) {
        console.error('Recipient mismatch');
        return false;
      }

      // Step 4: Check proof freshness (within 5 minutes)
      const proofAge = Date.now() - proofData.timestamp;
      if (proofAge > 5 * 60 * 1000) {
        console.error('Proof expired');
        return false;
      }

      // All checks passed
      return true;

    } catch (error) {
      console.error('ZK verification error:', error);
      return false;
    }
  }

  private generateRequestId(): string {
    return `zk_req_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
  }
}

export default X402ZKMiddleware;

```

### Step 4: Create x402 ZK API Server

```typescript
// server/app.ts
import express from 'express';
import X402ZKMiddleware from './x402ZKMiddleware';

const app = express();
app.use(express.json());

// Initialize x402 middleware with ZK support
const x402zk = new X402ZKMiddleware({
  merchantPhone: process.env.MERCHANT_PHONE || '+1234567890',
  merchantWallet: process.env.MERCHANT_WALLET,
  pricePerRequest: 0.10 // 10 cents per request
});

// Apply middleware to protected routes
app.use('/api/premium', x402zk.middleware.bind(x402zk));

// Protected endpoint - requires ZK proof
app.get('/api/premium/data', (req, res) => {
  res.json({
    message: 'Premium data with privacy',
    data: {
      insights: ['Market analysis', 'Private predictions'],
      privacy: 'Your payment was private via ZK proofs'
    },
    paymentInfo: {
      amountKnownByYou: true,
      amountKnownByMerchant: true,
      amountKnownByPublic: false,
      senderPrivate: true
    }
  });
});

// AI agent endpoint with privacy
app.post('/api/premium/ai-query', (req, res) => {
  const { query } = req.body;

  res.json({
    query: query,
    response: 'AI response with private payment',
    privacy: {
      yourIdentityHidden: true,
      amountEncrypted: true,
      phoneNumberPrivate: true
    }
  });
});

// Health check (free)
app.get('/health', (req, res) => {
  res.json({
    status: 'ok',
    service: 'numpay-zk-x402',
    features: ['zero-knowledge', 'phone-payments', 'zero-fees']
  });
});

const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
  console.log(`NumPay ZK x402 API running on port ${PORT}`);
  console.log('Privacy features: ZK proofs + ElGamal encryption + Phone linking');
});

```

### Step 5: Client-Side Integration

```typescript
// client/paymentClient.ts
import axios from 'axios';
import NumPayPrivateClient from './numpayZKClient';
import { generatePrivatePayment } from './generateProof';

class X402ZKPaymentClient {
  private client: NumPayPrivateClient;
  private apiUrl: string;

  constructor(
    phoneNumber: string,
    privateKey: string,
    apiUrl: string
  ) {
    this.client = new NumPayPrivateClient(privateKey, phoneNumber);
    this.apiUrl = apiUrl;
  }

  async initialize() {
    await this.client.initialize();
  }

  async makePrivateRequest(
    endpoint: string,
    options: {
      method?: 'GET' | 'POST';
      data?: any;
    } = {}
  ) {
    try {
      // Step 1: Try initial request
      const response = await axios({
        method: options.method || 'GET',
        url: `${this.apiUrl}${endpoint}`,
        data: options.data,
        validateStatus: (status) => status === 200 || status === 402
      });

      // Step 2: Check if payment required
      if (response.status === 402) {
        console.log('Payment required - generating private proof...');

        const instructions = response.data;

        // Step 3: Generate ZK proof for private payment
        const myPhone = await this.client.numpay.getPhoneNumber();
        const proof = await generatePrivatePayment(
          myPhone,
          instructions.payment.recipient.phone,
          instructions.payment.amount,
          endpoint
        );

        console.log('✓ ZK proof generated - submitting payment...');

        // Step 4: Verify proof with NumPay ZK verifier
        const verifyRes = await axios.post(
          instructions.payment.verifyEndpoint,
          proof
        );

        if (!verifyRes.data.valid) {
          throw new Error('Proof verification failed');
        }

        const paymentToken = verifyRes.data.paymentToken;
        console.log('✓ Proof verified - settling payment...');

        // Step 5: Settle payment (gasless via NumPay relayer)
        const settleRes = await axios.post(
          instructions.payment.settleEndpoint,
          {
            ...proof,
            paymentToken,
            resource: endpoint
          }
        );

        if (settleRes.data.status !== 'success') {
          throw new Error('Payment settlement failed');
        }

        console.log('✓ Payment settled privately!');
        console.log(`  - Your identity: HIDDEN via ZK`);
        console.log(`  - Amount: ENCRYPTED`);
        console.log(`  - Transaction: ${settleRes.data.txSignature}`);

        // Step 6: Retry request with payment proof
        const paidResponse = await axios({
          method: options.method || 'GET',
          url: `${this.apiUrl}${endpoint}`,
          data: options.data,
          headers: {
            'X-Payment-Proof': JSON.stringify({
              ...proof,
              paymentToken,
              txSignature: settleRes.data.txSignature
            })
          }
        });

        return paidResponse.data;
      }

      // No payment required
      return response.data;

    } catch (error) {
      console.error('Private request failed:', error);
      throw error;
    }
  }

  // Convenience: Pay to someone's phone number
  async sendPrivatePayment(
    recipientPhone: string,
    amount: number,
    memo?: string
  ) {
    const myPhone = await this.client.numpay.getPhoneNumber();

    const proof = await generatePrivatePayment(
      myPhone,
      recipientPhone,
      amount,
      memo || 'Direct payment'
    );

    // Verify and settle
    const verifyRes = await axios.post(
      'https://api.numpay.io/zk/verify',
      proof
    );

    const settleRes = await axios.post(
      'https://api.numpay.io/zk/settle',
      {
        ...proof,
        paymentToken: verifyRes.data.paymentToken
      }
    );

    return {
      success: true,
      txSignature: settleRes.data.txSignature,
      privacy: {
        amountEncrypted: true,
        senderHidden: true,
        recipientPhone: recipientPhone // Only you and recipient know
      }
    };
  }
}

export default X402ZKPaymentClient;

```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://numpay.gitbook.io/numpay/technology-architecture/numpay-shadow-protocol-zk-+-x402/integration-code.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
