Skip to main content

Complete Examples

Explore these comprehensive examples to see how Nevermined Payments works in practice.

AI Code Review Assistant

Monetize code review and analysis services

Multi-Tier Chat Agent

Offer different pricing tiers for AI chat services

Dynamic Pricing API

Charge based on request complexity

Proxy Integration

Add payments to existing services without code changes

AI Code Review Assistant

A complete example of an AI-powered code review service with payment integration.
import express from 'express'
import { 
  Payments, 
  getERC20PriceConfig, 
  getFixedCreditsConfig 
} from '@nevermined-io/payments'

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

// Initialize Nevermined
const payments = Payments.getInstance({
  nvmApiKey: process.env.NVM_API_KEY,
  environment: 'production'
})

// Setup function - run once to create agent
async function setupCodeReviewAgent() {
  const agentMetadata = {
    name: 'AI Code Review Assistant',
    tags: ['development', 'code-review', 'ai', 'typescript'],
    dateCreated: new Date(),
    description: 'Advanced AI-powered code review with security analysis and best practice suggestions'
  }

  const agentApi = {
    endpoints: [
      { POST: 'https://api.codereview.ai/review' },
      { POST: 'https://api.codereview.ai/security-scan' },
      { GET: 'https://api.codereview.ai/status' }
    ],
    openEndpoints: ['https://api.codereview.ai/health']
  }

  // 10 USDC for 100 reviews
  const priceConfig = getERC20PriceConfig(
    10_000_000n, // 10 USDC
    '0xA0b86a33E6441c41F4F2B8Bf4F2B0f1B0F1C1C1C',
    process.env.BUILDER_ADDRESS
  )

  const creditsConfig = getFixedCreditsConfig(100n, 1n)

  const { agentId, planId } = await payments.registerAgentAndPlan(
    agentMetadata,
    agentApi,
    priceConfig,
    creditsConfig
  )

  console.log(`Code Review Agent: ${agentId}`)
  console.log(`Basic Plan: ${planId}`)
  
  return { agentId, planId }
}

// Middleware for Nevermined authentication
function requirePayment(planId: string, agentId: string) {
  return async (req, res, next) => {
    try {
      const isValid = await payments.isValidRequest(
        planId,
        agentId,
        req.body.subscriberAddress,
        req.headers['x-nvm-query-signature']
      )

      if (!isValid) {
        const paymentCard = await payments.getAgentPaymentCard(agentId)
        return res.status(402).json({
          error: 'Payment required',
          message: 'Purchase a plan to access this service',
          paymentCard
        })
      }

      req.nevermined = { planId, agentId }
      next()
    } catch (error) {
      console.error('Auth error:', error)
      res.status(500).json({ error: 'Authentication failed' })
    }
  }
}

// Main code review endpoint
app.post('/review', 
  requirePayment(process.env.PLAN_ID, process.env.AGENT_ID),
  async (req, res) => {
    try {
      const { code, language, rules } = req.body

      // Perform AI code review
      const review = await performCodeReview(code, language, rules)

      // Track usage
      const proof = {
        requestId: req.id,
        timestamp: new Date().toISOString(),
        codeLength: code.length,
        language
      }

      // Redeem credits
      await payments.redeemCredits(
        req.nevermined.planId,
        1n,
        proof
      )

      // Get remaining balance
      const balance = await payments.getPlanBalance(
        req.nevermined.planId,
        req.body.subscriberAddress
      )

      res.json({
        review,
        credits: {
          used: 1,
          remaining: balance.credits.toString()
        }
      })
    } catch (error) {
      console.error('Review error:', error)
      res.status(500).json({ error: 'Review failed' })
    }
  }
)

// Security scan endpoint (uses more credits)
app.post('/security-scan',
  requirePayment(process.env.PLAN_ID, process.env.AGENT_ID),
  async (req, res) => {
    try {
      const { code, language } = req.body
      
      // This endpoint uses 5 credits
      const creditsRequired = 5n
      
      // Check balance first
      const balance = await payments.getPlanBalance(
        req.nevermined.planId,
        req.body.subscriberAddress
      )
      
      if (balance.credits < creditsRequired) {
        return res.status(402).json({
          error: 'Insufficient credits',
          required: creditsRequired.toString(),
          available: balance.credits.toString()
        })
      }

      const scan = await performSecurityScan(code, language)

      await payments.redeemCredits(
        req.nevermined.planId,
        creditsRequired,
        { scan: scan.id, severity: scan.highestSeverity }
      )

      res.json({
        scan,
        credits: {
          used: creditsRequired.toString(),
          remaining: (balance.credits - creditsRequired).toString()
        }
      })
    } catch (error) {
      console.error('Scan error:', error)
      res.status(500).json({ error: 'Security scan failed' })
    }
  }
)

// Health check (open endpoint)
app.get('/health', (req, res) => {
  res.json({ status: 'healthy', service: 'code-review' })
})

// Mock review functions
async function performCodeReview(code, language, rules) {
  // Your AI code review logic here
  return {
    score: 85,
    issues: [
      { line: 10, severity: 'warning', message: 'Consider using const instead of let' },
      { line: 25, severity: 'info', message: 'Function could be simplified' }
    ],
    suggestions: ['Add error handling', 'Consider adding unit tests']
  }
}

async function performSecurityScan(code, language) {
  // Your security scanning logic here
  return {
    id: 'scan-' + Date.now(),
    vulnerabilities: [],
    highestSeverity: 'low',
    recommendations: ['Enable strict mode', 'Validate user input']
  }
}

app.listen(3000, () => {
  console.log('Code Review Service running on port 3000')
})

Multi-Tier Chat Agent

Example of an AI chat service with multiple pricing tiers.
import { 
  Payments, 
  getERC20PriceConfig, 
  getFixedCreditsConfig,
  getExpirablePlanCreditsConfig,
  getFiatPriceConfig
} from '@nevermined-io/payments'

async function createMultiTierChatAgent() {
  const payments = Payments.getInstance({
    nvmApiKey: process.env.NVM_API_KEY,
    environment: 'production'
  })

  const agentMetadata = {
    name: 'Advanced AI Chat Assistant',
    tags: ['chat', 'ai', 'gpt-4', 'enterprise'],
    dateCreated: new Date(),
    description: 'Enterprise-grade AI chat with multiple models and capabilities',
    image: 'https://example.com/chat-logo.png'
  }

  const agentApi = {
    endpoints: [
      { POST: 'https://api.chat.ai/v1/chat' },
      { POST: 'https://api.chat.ai/v1/chat/stream' },
      { GET: 'https://api.chat.ai/v1/models' }
    ]
  }

  // Basic Plan - 5 USDC for 50 messages
  const basicPrice = getERC20PriceConfig(
    5_000_000n,
    '0xA0b86a33E6441c41F4F2B8Bf4F2B0f1B0F1C1C1C',
    process.env.BUILDER_ADDRESS
  )
  const basicCredits = getFixedCreditsConfig(50n, 1n)
  const { planId: basicPlanId } = await payments.registerCreditsPlan(
    basicPrice,
    basicCredits
  )

  // Premium Plan - 20 USDC for 250 messages  
  const premiumPrice = getERC20PriceConfig(
    20_000_000n,
    '0xA0b86a33E6441c41F4F2B8Bf4F2B0f1B0F1C1C1C',
    process.env.BUILDER_ADDRESS
  )
  const premiumCredits = getFixedCreditsConfig(250n, 1n)
  const { planId: premiumPlanId } = await payments.registerCreditsPlan(
    premiumPrice,
    premiumCredits
  )

  // Enterprise Plan - $100/month unlimited (via Stripe)
  const enterprisePrice = getFiatPriceConfig(
    100_000_000n, // $100
    process.env.BUILDER_ADDRESS
  )
  const enterpriseCredits = getExpirablePlanCreditsConfig(86400n * 30n) // 30 days
  const { planId: enterprisePlanId } = await payments.registerTimePlan(
    enterprisePrice,
    enterpriseCredits
  )

  // Register agent with all plans
  const { agentId } = await payments.registerAgent(
    agentMetadata,
    agentApi,
    [basicPlanId, premiumPlanId, enterprisePlanId]
  )

  return {
    agentId,
    plans: {
      basic: basicPlanId,
      premium: premiumPlanId,
      enterprise: enterprisePlanId
    }
  }
}

// Express server implementation
app.post('/v1/chat', async (req, res) => {
  const { message, model, subscriberAddress, planId } = req.body
  const signature = req.headers['x-nvm-query-signature']
  
  // Find which plan they're using
  const agentId = process.env.AGENT_ID
  const agent = await payments.getAgent(agentId)
  const plan = agent.plans.find(p => p.planId === planId)
  
  if (!plan) {
    return res.status(400).json({ error: 'Invalid plan' })
  }

  // Validate access
  const isValid = await payments.isValidRequest(
    planId,
    agentId,
    subscriberAddress,
    signature
  )

  if (!isValid) {
    const paymentCard = await payments.getAgentPaymentCard(agentId)
    return res.status(402).json({
      error: 'Payment required',
      paymentCard,
      availablePlans: agent.plans.map(p => ({
        id: p.planId,
        name: p.metadata.name,
        price: p.price.amounts[0],
        credits: p.credits.amount,
        features: getFeaturesByPlan(p.planId)
      }))
    })
  }

  // Route to appropriate model based on plan
  const modelToUse = getModelByPlan(plan.planId, model)
  const response = await generateChatResponse(message, modelToUse)

  // Calculate credits based on response length
  const creditsUsed = plan.credits.creditsType === 'DYNAMIC' 
    ? calculateDynamicCredits(response)
    : 1n

  await payments.redeemCredits(planId, creditsUsed, {
    model: modelToUse,
    tokens: response.usage.totalTokens
  })

  res.json({
    response: response.content,
    model: modelToUse,
    usage: {
      creditsUsed: creditsUsed.toString(),
      tokensUsed: response.usage.totalTokens
    }
  })
})

function getModelByPlan(planId: string, requestedModel: string): string {
  const planModels = {
    [process.env.BASIC_PLAN_ID]: ['gpt-3.5-turbo'],
    [process.env.PREMIUM_PLAN_ID]: ['gpt-3.5-turbo', 'gpt-4'],
    [process.env.ENTERPRISE_PLAN_ID]: ['gpt-3.5-turbo', 'gpt-4', 'gpt-4-turbo']
  }
  
  const allowedModels = planModels[planId] || ['gpt-3.5-turbo']
  return allowedModels.includes(requestedModel) ? requestedModel : allowedModels[0]
}

function getFeaturesByPlan(planId: string) {
  const features = {
    [process.env.BASIC_PLAN_ID]: ['GPT-3.5', '50 messages', 'Standard support'],
    [process.env.PREMIUM_PLAN_ID]: ['GPT-4', '250 messages', 'Priority support'],
    [process.env.ENTERPRISE_PLAN_ID]: ['All models', 'Unlimited', '24/7 support', 'Custom integration']
  }
  return features[planId] || []
}

Dynamic Pricing API

Example of dynamic credit consumption based on request complexity.
async function createDynamicPricingAgent() {
  const payments = Payments.getInstance({
    nvmApiKey: process.env.NVM_API_KEY,
    environment: 'production'
  })

  const agentMetadata = {
    name: 'AI Data Analysis Service',
    tags: ['data', 'analysis', 'ml', 'dynamic-pricing'],
    dateCreated: new Date(),
    description: 'Advanced data analysis with pricing based on complexity'
  }

  const agentApi = {
    endpoints: [
      { POST: 'https://api.dataanalysis.ai/analyze' }
    ]
  }

  // Dynamic pricing: 50 USDC for 1000 credits
  const priceConfig = getERC20PriceConfig(
    50_000_000n,
    '0xA0b86a33E6441c41F4F2B8Bf4F2B0f1B0F1C1C1C',
    process.env.BUILDER_ADDRESS
  )

  const dynamicCredits = {
    creditsType: 'DYNAMIC',
    minCreditsPerRequest: 1n,
    maxCreditsPerRequest: 50n,
    amount: 1000n
  }

  const { agentId, planId } = await payments.registerAgentAndPlan(
    agentMetadata,
    agentApi,
    priceConfig,
    dynamicCredits
  )

  return { agentId, planId }
}

// Dynamic pricing endpoint
app.post('/analyze', async (req, res) => {
  const { data, analysisType, depth } = req.body
  
  // Validate access
  const isValid = await payments.isValidRequest(
    req.body.planId,
    req.body.agentId,
    req.body.subscriberAddress,
    req.headers['x-nvm-query-signature']
  )

  if (!isValid) {
    const paymentCard = await payments.getAgentPaymentCard(req.body.agentId)
    return res.status(402).json({ error: 'Payment required', paymentCard })
  }

  // Check balance before processing
  const balance = await payments.getPlanBalance(
    req.body.planId,
    req.body.subscriberAddress
  )

  // Calculate complexity and required credits
  const complexity = calculateComplexity(data, analysisType, depth)
  const creditsRequired = BigInt(Math.min(Math.max(complexity, 1), 50))

  if (balance.credits < creditsRequired) {
    return res.status(402).json({
      error: 'Insufficient credits',
      required: creditsRequired.toString(),
      available: balance.credits.toString(),
      complexity: complexity
    })
  }

  // Perform analysis
  const startTime = Date.now()
  const analysis = await performDataAnalysis(data, analysisType, depth)
  const processingTime = Date.now() - startTime

  // Redeem credits based on actual complexity
  await payments.redeemCredits(
    req.body.planId,
    creditsRequired,
    {
      analysisId: analysis.id,
      dataPoints: data.length,
      processingTime,
      complexity
    }
  )

  res.json({
    analysis,
    billing: {
      creditsUsed: creditsRequired.toString(),
      creditsRemaining: (balance.credits - creditsRequired).toString(),
      complexity,
      processingTime
    }
  })
})

function calculateComplexity(data: any[], analysisType: string, depth: string): number {
  const baseComplexity = {
    'basic': 1,
    'intermediate': 5,
    'advanced': 10,
    'ml-powered': 20
  }

  const depthMultiplier = {
    'shallow': 1,
    'normal': 2,
    'deep': 3
  }

  const base = baseComplexity[analysisType] || 1
  const multiplier = depthMultiplier[depth] || 1
  const dataMultiplier = Math.ceil(data.length / 1000) // Per 1000 data points

  return base * multiplier * dataMultiplier
}

Proxy Integration Example

Use Nevermined Proxy to add payments to existing services without modifying code.
// For existing services, no code changes needed!
// Just register your service with Nevermined

async function setupProxyIntegration() {
  const payments = Payments.getInstance({
    nvmApiKey: process.env.NVM_API_KEY,
    environment: 'production'
  })

  // Register your existing service
  const agentMetadata = {
    name: 'Legacy AI Service',
    tags: ['legacy', 'proxy', 'no-code'],
    dateCreated: new Date(),
    description: 'Existing AI service monetized through Nevermined Proxy'
  }

  const agentApi = {
    endpoints: [
      // Your existing endpoints
      { POST: 'https://legacy-api.example.com/v1/process' },
      { GET: 'https://legacy-api.example.com/v1/status' }
    ],
    // Public endpoints that don't require payment
    openEndpoints: [
      'https://legacy-api.example.com/health',
      'https://legacy-api.example.com/version'
    ]
  }

  const priceConfig = getERC20PriceConfig(
    15_000_000n, // 15 USDC
    '0xA0b86a33E6441c41F4F2B8Bf4F2B0f1B0F1C1C1C',
    process.env.BUILDER_ADDRESS
  )

  const creditsConfig = getFixedCreditsConfig(100n, 1n)

  const { agentId, planId } = await payments.registerAgentAndPlan(
    agentMetadata,
    agentApi,
    priceConfig,
    creditsConfig
  )

  console.log(`
    Legacy service registered!
    Agent ID: ${agentId}
    Plan ID: ${planId}
    
    Users can now access your service through:
    https://proxy.nevermined.app/agent/${agentId}
    
    The proxy handles all payment validation and credit redemption.
    No changes needed to your existing service!
  `)
}

// Client code to use the proxied service
async function useProxiedService() {
  const payments = Payments.getInstance({
    nvmApiKey: process.env.NVM_API_KEY,
    environment: 'production'
  })

  // Purchase plan
  await payments.orderPlan(planId)

  // Get access credentials
  const options = await payments.getAgentHTTPOptions(planId, agentId)

  // Query through proxy
  const response = await fetch(options.neverminedProxyUri, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'Authorization': `Bearer ${options.accessToken}`
    },
    body: JSON.stringify({
      // Your original API payload
      data: 'process this data'
    })
  })

  const result = await response.json()
  console.log('Result from legacy service:', result)
}

Testing Your Integration

Example test suite for your Nevermined integration:
import { Payments } from '@nevermined-io/payments'

describe('Nevermined Integration Tests', () => {
  let payments: Payments
  let testAgentId: string
  let testPlanId: string

  beforeAll(async () => {
    // Use testing environment
    payments = Payments.getInstance({
      nvmApiKey: process.env.NVM_TEST_API_KEY,
      environment: 'testing'
    })

    // Create test agent
    const result = await payments.registerAgentAndPlan(
      {
        name: 'Test Agent',
        tags: ['test'],
        dateCreated: new Date()
      },
      {
        endpoints: [{ POST: 'https://test.example.com/api' }]
      },
      getERC20PriceConfig(1_000_000n, TEST_TOKEN_ADDRESS, TEST_BUILDER_ADDRESS),
      getFixedCreditsConfig(10n, 1n)
    )

    testAgentId = result.agentId
    testPlanId = result.planId
  })

  test('should create agent successfully', () => {
    expect(testAgentId).toBeDefined()
    expect(testPlanId).toBeDefined()
  })

  test('should validate authorized requests', async () => {
    // Mock valid signature
    const isValid = await payments.isValidRequest(
      testPlanId,
      testAgentId,
      TEST_SUBSCRIBER_ADDRESS,
      'valid-signature'
    )
    
    expect(isValid).toBe(true)
  })

  test('should reject unauthorized requests', async () => {
    const isValid = await payments.isValidRequest(
      testPlanId,
      testAgentId,
      'unauthorized-address',
      'invalid-signature'
    )
    
    expect(isValid).toBe(false)
  })

  test('should track credit usage', async () => {
    const initialBalance = await payments.getPlanBalance(
      testPlanId,
      TEST_SUBSCRIBER_ADDRESS
    )

    await payments.redeemCredits(testPlanId, 1n, { test: true })

    const newBalance = await payments.getPlanBalance(
      testPlanId,
      TEST_SUBSCRIBER_ADDRESS
    )

    expect(newBalance.credits).toBe(initialBalance.credits - 1n)
  })
})

Resources