Documentation Index
Fetch the complete documentation index at: https://docs.prudra.dev/llms.txt
Use this file to discover all available pages before exploring further.
Test MPP payments
MPP testing requires either stub mode (no real blockchain) or a funded Tempo testnet wallet. Start with stub mode, then graduate to testnet once your integration is working.
Stub mode (recommended for initial testing)
Set PAYMENT_STUB_MODE=true on your server. In stub mode, the server accepts any payment credential without calling the Tempo RPC.
PAYMENT_STUB_MODE=true PRUDRA_API_KEY=prv_test_sk_... npx ts-node server.ts
Test with the stub payment header:
curl -X POST http://localhost:4001/analyse \
-H "Content-Type: application/json" \
-H "X-PAYMENT: stub_payment_accepted" \
-d '{"text": "analyse this"}'
Testnet setup
For full end-to-end testing with real Tempo transactions:
- Get a Tempo testnet RPC URL (from your Tempo provider)
- Fund a test wallet with testnet USDC.e from the faucet
- Set
PAYMENT_STUB_MODE=false and configure your Tempo RPC URL
PAYMENT_STUB_MODE=false
TEMPO_RPC_URL=https://tempo-testnet.example.com/v2/your-key
TEMPO_CHAIN_ID=<testnet-chain-id>
USDC_E_CONTRACT=<testnet-usdc-e-address>
The MPP agent test script
This script demonstrates the full MPP agent flow from example-07-mpp-agent.ts:
import { ethers, JsonRpcProvider } from 'ethers';
import { parseMPPChallenge, buildMPPCredential } from '@prudra/payments';
const SERVER_URL = 'http://localhost:4001';
const TEMPO_RPC = process.env.TEMPO_RPC_URL!;
// ERC-20 ABI — compatible with Tempo's TIP-20 tokens
const ERC20_ABI = [
'function transfer(address to, uint256 amount) returns (bool)',
'function decimals() view returns (uint8)',
];
async function runMPPAgent() {
const provider = new JsonRpcProvider(TEMPO_RPC);
const agentWallet = new ethers.Wallet(process.env.AGENT_PRIVATE_KEY!, provider);
console.log('Agent wallet:', agentWallet.address);
// Step 1: Request without payment — get 402 with WWW-Authenticate
console.log('\nStep 1: Get MPP challenge');
const r1 = await fetch(`${SERVER_URL}/summarise`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ text: 'Summarise this' }),
});
console.log('Status:', r1.status); // 402
const wwwAuth = r1.headers.get('www-authenticate');
if (!wwwAuth) throw new Error('No WWW-Authenticate header');
// Step 2: Parse the MPP challenge
console.log('\nStep 2: Parse MPP challenge');
const challenge = parseMPPChallenge(wwwAuth);
console.log('Challenge ID:', challenge.id);
console.log('Realm:', challenge.realm);
console.log('Intent:', challenge.intent);
// Decode the request field to get payment details
const paymentRequest = JSON.parse(
Buffer.from(challenge.request, 'base64url').toString()
);
console.log('Amount:', paymentRequest.amount, 'base units');
console.log('Recipient:', paymentRequest.recipient);
// Step 3: Send on-chain transaction on Tempo
console.log('\nStep 3: Send USDC.e transaction on Tempo');
const usdce = new ethers.Contract(
process.env.USDC_E_CONTRACT!,
ERC20_ABI,
agentWallet
);
const decimals = await usdce.decimals();
const amount = BigInt(paymentRequest.amount); // already in base units
const tx = await usdce.transfer(paymentRequest.recipient, amount);
console.log('Transaction sent:', tx.hash);
const receipt = await tx.wait(1); // wait for 1 Tempo confirmation
console.log('Confirmed in block:', receipt.blockNumber);
// Step 4: Build credential and resubmit
console.log('\nStep 4: Resubmit with Authorization: Payment header');
const credential = buildMPPCredential({
id: challenge.id,
txHash: tx.hash,
from: agentWallet.address,
chainId: parseInt(process.env.TEMPO_CHAIN_ID!),
});
const r2 = await fetch(`${SERVER_URL}/summarise`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Payment ${credential}`,
},
body: JSON.stringify({ text: 'Summarise this' }),
});
console.log('Status:', r2.status); // 200
const result = await r2.json();
console.log('\nResult:', JSON.stringify(result, null, 2));
console.log('Vault ID:', result.vaultId);
console.log('Protocol:', result.payment?.protocol); // 'mpp'
}
runMPPAgent().catch(err => {
console.error('Fatal:', err.message);
process.exit(1);
});
Run the test
AGENT_PRIVATE_KEY=0x... \
TEMPO_RPC_URL=https://tempo-testnet... \
TEMPO_CHAIN_ID=<testnet-id> \
USDC_E_CONTRACT=0x... \
npx ts-node example-07-mpp-agent.ts