Skip to main content
This guide gets you from zero to a working payment integration in 5 minutes. By the end, you’ll have a monetizable service set up with Nevermined — typically an agent API, but the same flow applies to MCP tools/servers and protected assets.
In the code below we use “agent” terminology because it maps to the underlying object model, but you can think of it as the service/resource you’re charging for.

Prerequisites

1

Get Your API Key

  1. Go to nevermined.app and sign in
  2. Navigate to Settings > API Keys
  3. Generate a new key and copy it
export NVM_API_KEY="nvm:your-api-key-here"
2

Install the SDK

npm install @nevermined-io/payments

Register Your Service (2 minutes)

Create a file to register your service and a payment plan. If you’re monetizing an MCP tool/server or a protected resource, you’ll still register the monetizable unit and attach a plan — only the delivery step changes.
import { Payments, getERC20PriceConfig, getFixedCreditsConfig } from '@nevermined-io/payments'

const USDC_ADDRESS = '0x036CbD53842c5426634e7929541eC2318f3dCF7e' // Base Sepolia USDC

async function main() {
  // 1. Initialize the SDK
  const payments = Payments.getInstance({
    nvmApiKey: process.env.NVM_API_KEY!,
    environment: 'testing'
  })

  // 2. Register service + payment plan ("agent" in the SDK)
  const { agentId, planId } = await payments.agents.registerAgentAndPlan(
    // Service metadata
    {
      name: 'My AI Assistant',
      description: 'A paid service (agent API / MCP tool / protected resource)',
      tags: ['ai', 'payments'],
      dateCreated: new Date()
    },
    // Service interface - replace with your endpoint
    {
      endpoints: [{ POST: 'https://your-api.com/query' }]
    },
    // Plan metadata
    {
      name: 'Starter Plan',
      description: '100 requests for $10',
      dateCreated: new Date()
    },
    // Price: 10 USDC
    getERC20PriceConfig(
      10_000_000n, // 10 USDC (6 decimals)
      USDC_ADDRESS,
      process.env.BUILDER_ADDRESS! // Your wallet address
    ),
    // Credits: 100 requests, 1 credit each
    getFixedCreditsConfig(100n, 1n),
    'credits'
  )

  console.log('Registered!')
  console.log(`Service (agent) ID: ${agentId}`)
  console.log(`Plan ID: ${planId}`)
  console.log('\nSave these IDs for your integration.')
}

main().catch(console.error)
Run it:
npx ts-node register-agent.ts

Add Payment Validation (3 minutes)

Add this middleware to validate entitlement before delivering your response/resource. The example shows an HTTP API route; the same check can be used before calling an MCP tool handler or before serving a protected asset:
import { Payments } from '@nevermined-io/payments'
import { Request, Response, NextFunction } from 'express'

const payments = Payments.getInstance({
  nvmApiKey: process.env.NVM_API_KEY!,
  environment: 'testing'
})

// Your registered IDs
const PLAN_ID = 'did:nv:your-plan-id'
const AGENT_ID = 'did:nv:your-agent-id'

export async function validatePayment(
  req: Request,
  res: Response,
  next: NextFunction
) {
  const authHeader = req.headers['authorization']

  // Check for Bearer token
  if (!authHeader || !authHeader.startsWith('Bearer ')) {
    return res.status(402).json({
      error: 'Payment Required',
      message: 'Purchase a plan to access this API',
      plans: [{ planId: PLAN_ID, agentId: AGENT_ID }]
    })
  }

  const token = authHeader.substring(7)

  // Validate the request
  const { isValid, balance } = await payments.requests.isValidRequest(
    token,
    req.body
  )

  if (!isValid) {
    return res.status(402).json({
      error: 'Payment Required',
      message: 'Insufficient credits or invalid token',
      plans: [{ planId: PLAN_ID, agentId: AGENT_ID }]
    })
  }

  // Attach balance to request for optional use
  req.creditsRemaining = balance

  next()
}

Use the Middleware

import express from 'express'
import { validatePayment } from './middleware/payments'

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

// Protected endpoint
app.post('/query', validatePayment, async (req, res) => {
  // Your AI logic here
  const result = await processQuery(req.body.prompt)

  res.json({
    result,
    creditsRemaining: req.creditsRemaining
  })
})

app.listen(3000, () => {
  console.log('Agent running on http://localhost:3000')
})

Test It

1) Try without payment (should fail)
curl -X POST http://localhost:3000/query \
  -H "Content-Type: application/json" \
  -d '{"prompt": "Hello"}'
Response:
{
  "error": "Payment Required",
  "message": "Purchase a plan to access this API",
  "plans": [{"planId": "did:nv:...", "agentId": "did:nv:..."}]
}
2) Purchase a plan and get an access token
// As a subscriber
const payments = Payments.getInstance({ nvmApiKey: subscriberKey, environment: 'testing' })

// Order the plan
await payments.plans.orderPlan(PLAN_ID)

// Get access token
const { accessToken } = await payments.agents.getAgentAccessToken(PLAN_ID, AGENT_ID)
3) Query with payment
curl -X POST http://localhost:3000/query \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -d '{"prompt": "Hello"}'
Response:
{
  "result": "Hello! How can I help you today?",
  "creditsRemaining": 99
}

What’s Next?