Integration Guide

Consuming an MPP API

Learn how to call an AI agent through the MPP Gateway, handle the HTTP 402 challenge, and construct a Solana payment transaction programmatically.


The HTTP 402 Flow

Unlike traditional APIs where you attach a static Authorization: Bearer <token> header, MPP requires a cryptographic proof of payment for every single request.

The lifecycle of a request looks like this:

  1. Initial Request: You send a standard HTTP request to the MPP Gateway without any authentication.
  2. The Challenge: The Gateway responds with 402 Payment Required and provides the payment details (amount, provider wallet, platform fee wallet) in the WWW-Authenticate header.
  3. Payment: Your application uses @solana/web3.js to construct a transaction sending funds to the provider and platform, and signs it with your private key.
  4. Retry: You resend the exact same HTTP request, but this time you attach the transaction signature in the headers.
  5. Success: The Gateway verifies the payment on-chain and proxies your request to the underlying AI model.

TypeScript Implementation

Below is a complete, working example of how to consume an MPP endpoint using Node.js and the official @solana/web3.js SDK.

mpp-client.ts
import { Connection, Keypair, SystemProgram, Transaction, sendAndConfirmTransaction } from "@solana/web3.js";
import fetch from "node-fetch";

// 1. Setup your Solana Wallet (Consumer)
const privateKey = new Uint8Array([/* YOUR PRIVATE KEY ARRAY */]);
const consumerWallet = Keypair.fromSecretKey(privateKey);
const connection = new Connection("https://api.mainnet-beta.solana.com", "confirmed");

async function callAIAgent(prompt: string) {
  const url = "https://api.mpp.dev/v1/gateway/defi-sentiment";
  const body = JSON.stringify({ prompt });

  // 2. Initial Request (Will fail with 402)
  console.log("Sending initial request...");
  let res = await fetch(url, {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body
  });

  if (res.status === 402) {
    // 3. Extract the Challenge
    const challenge = res.headers.get("WWW-Authenticate");
    console.log("Received 402 Challenge:", challenge);
    
    // Parse the challenge string (simplified for example)
    // Expected: Payment address="ProviderPubKey", amount="0.5", fee_wallet="PlatformPubKey", fee_percent="2%"
    const providerAddr = challenge.match(/address="([^"]+)"/)[1];
    const amountStr = challenge.match(/amount="([^"]+)"/)[1];
    const feeWalletAddr = challenge.match(/fee_wallet="([^"]+)"/)[1];
    
    const totalAmount = parseFloat(amountStr) * 1e9; // Convert SOL to Lamports
    const platformFee = totalAmount * 0.02; // 2%
    const providerAmount = totalAmount - platformFee;

    // 4. Construct the P2P Transaction
    console.log("Building Solana Transaction...");
    const transaction = new Transaction().add(
      // Transfer to Provider
      SystemProgram.transfer({
        fromPubkey: consumerWallet.publicKey,
        toPubkey: new PublicKey(providerAddr),
        lamports: providerAmount,
      }),
      // Transfer 2% Fee to Platform
      SystemProgram.transfer({
        fromPubkey: consumerWallet.publicKey,
        toPubkey: new PublicKey(feeWalletAddr),
        lamports: platformFee,
      })
    );

    // 5. Sign and Send
    const signature = await sendAndConfirmTransaction(connection, transaction, [consumerWallet]);
    console.log("Payment Confirmed! Signature:", signature);

    // 6. Retry Request with Signature
    res = await fetch(url, {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
        "Authorization": `Payment signature=${signature}`
      },
      body
    });
  }

  // 7. Get final AI response
  const data = await res.json();
  console.log("AI Response:", data);
}

callAIAgent("Is Solana trending bullish today?");

Security Best Practice

For production applications, do not hardcode private keys in your source code. Use environment variables or a secure key management system (KMS). If building a web application, use a wallet adapter extension (like Phantom) to let users sign transactions manually.

cURL Example

If you have already executed a transaction and have a valid signature, you can test the API directly from your terminal:

curl -X POST https://api.mpp.dev/v1/gateway/defi-sentiment \
  -H "Content-Type: application/json" \
  -H "Authorization: Payment signature=5gP...your_signature_here...3bQ" \
  -d '{"prompt": "Analyze market trends"}'

Python Implementation

Here is an equivalent example for Python developers using the solana package.

client.py
import requests
from solana.rpc.api import Client
from solders.keypair import Keypair
from solders.pubkey import Pubkey
from solders.system_program import TransferParams, transfer
from solana.transaction import Transaction
import re

# Setup Wallet
keypair = Keypair.from_bytes(b'\x00' * 64) # Replace with real private key
solana_client = Client("https://api.mainnet-beta.solana.com")
url = "https://api.mpp.dev/v1/gateway/defi-sentiment"

# Initial Request (Expect 402)
response = requests.post(url, json={"prompt": "Is Solana trending bullish today?"})

if response.status_code == 402:
    challenge = response.headers.get("WWW-Authenticate")
    
    # Parse challenge (simplified)
    provider_addr = re.search(r'address="([^"]+)"', challenge).group(1)
    amount_str = re.search(r'amount="([^"]+)"', challenge).group(1)
    fee_wallet = re.search(r'fee_wallet="([^"]+)"', challenge).group(1)
    
    total_lamports = int(float(amount_str) * 1e9)
    fee_lamports = int(total_lamports * 0.02)
    provider_lamports = total_lamports - fee_lamports
    
    # Build Transaction
    txn = Transaction()
    txn.add(transfer(TransferParams(from_pubkey=keypair.pubkey(), to_pubkey=Pubkey.from_string(provider_addr), lamports=provider_lamports)))
    txn.add(transfer(TransferParams(from_pubkey=keypair.pubkey(), to_pubkey=Pubkey.from_string(fee_wallet), lamports=fee_lamports)))
    
    # Sign and Send
    result = solana_client.send_transaction(txn, keypair)
    signature = result.value
    print("Signature:", signature)
    
    # Retry Request
    headers = {"Authorization": f"Payment signature={signature}"}
    final_response = requests.post(url, json={"prompt": "Is Solana trending bullish today?"}, headers=headers)
    
    print("AI Response:", final_response.json())

Note: Transaction signatures can only be used once per request to prevent replay attacks. The MPP Gateway tracks signatures and enforces idempotency.

Built for the machine economy by MPP Layer.