| name | nevermined-payments |
| version | 0.3.3 |
| lastUpdated | 2026-05-06 |
| description | Integrates Nevermined payment infrastructure into AI agents, MCP servers, Google A2A agents, and REST APIs. Handles x402 protocol, credit billing, payment plans, and SDK integration for TypeScript (@nevermined-io/payments) and Python (payments-py).
|
| metadata | {"openclaw":{"primaryEnv":"NVM_API_KEY","requires":{"env":["NVM_API_KEY"]},"envVars":[{"name":"NVM_API_KEY","required":true,"description":"Nevermined API key used by the SDK, REST API, and CLI. Format `sandbox:...` for the sandbox environment, `live:...` for production. Issued from https://nevermined.app under API Keys.\n"}]}} |
Nevermined Payments Integration
Skill version: 0.3.3 | Last updated: 2026-05-06
Verified against @nevermined-io/payments@1.3.3 and payments-py@1.5.0.
Overview
Nevermined provides financial rails for AI agents — real-time monetization, access control, and payments. This skill gives you everything needed to:
- Protect API endpoints with the x402 payment protocol
- Charge per-request using credit-based billing
- Integrate with Express.js, FastAPI, Strands agents, MCP servers, or Google A2A agents
- Support subscriber-side flows (purchase plans, generate tokens, call protected APIs)
- Enable agent-to-agent payments via the Google A2A protocol
The x402 protocol uses HTTP 402 responses to advertise payment requirements. Clients acquire an access token and retry the request. The server verifies permissions, executes the workload, then settles (burns credits).
Nevermined API Key Prerequisite
A Nevermined API Key (NVM_API_KEY) is required for ALL interactions with the Nevermined platform — SDK initialization, REST API calls, CLI usage, and agent registration. Without it, nothing works.
If the developer already has a key, they can skip this section and set it as an environment variable:
export NVM_API_KEY="sandbox:your-api-key"
If the developer does NOT have a key, guide them through these steps:
- Open nevermined.app and sign in
- Navigate to Settings > Global NVM API Keys
- Click + New API Key
- Enter a descriptive name, select the required permissions, and click Generate API Key
- Click Copy Key and store it securely as an environment variable (
NVM_API_KEY)
The key format is <environment>:<hash> — for example sandbox:eyJhbGci... or live:eyJhbGci....
Full documentation: Get Your API Key
IMPORTANT for AI agents: If you are generating code that requires NVM_API_KEY and the developer has not provided one, you MUST tell them to create one first by following the steps above or visiting nevermined.app. Never generate placeholder keys that look real. Always use sandbox:your-api-key as the placeholder value.
Quick Start Checklist
- Get an API key — see Nevermined API Key Prerequisite above
- Install the SDK (
npm install @nevermined-io/payments or pip install payments-py)
- Register your agent and plan (via the App UI or programmatically — see
references/payment-plans.md)
- Add payment protection to your routes/tools (see framework-specific references below)
- Test — call without token (expect 402), then with token (expect 200)
Environment Setup
| Variable | Required | Description |
|---|
NVM_API_KEY | Yes | Your Nevermined API key — see Get Your API Key |
NVM_ENVIRONMENT | Yes | sandbox for testing, live for production |
NVM_PLAN_ID | Yes | The plan ID from registration |
NVM_AGENT_ID | Sometimes | Required for MCP servers and plans with multiple agents |
BUILDER_ADDRESS | For registration | Wallet address to receive payments |
.env Template
NVM_API_KEY=sandbox:your-api-key
NVM_ENVIRONMENT=sandbox
NVM_PLAN_ID=your-plan-id-here
NVM_AGENT_ID=your-agent-id-here
BUILDER_ADDRESS=0xYourWalletAddress
Prerequisites
- TypeScript/Express.js: Node.js 18+. Your
package.json must include "type": "module" for the @nevermined-io/payments/express subpath import to work.
- Python/FastAPI: Python 3.9+. Install with
pip install payments-py[fastapi] — the [fastapi] extra is required for the middleware.
TypeScript
npm install @nevermined-io/payments
import { Payments } from '@nevermined-io/payments'
const payments = Payments.getInstance({
nvmApiKey: process.env.NVM_API_KEY!,
environment: 'sandbox'
})
Python
pip install payments-py
import os
from payments_py import Payments, PaymentOptions
payments = Payments.get_instance(
PaymentOptions(
nvm_api_key=os.environ["NVM_API_KEY"],
environment="sandbox"
)
)
Core Workflow (All Integrations)
Every Nevermined payment integration follows this 5-step pattern:
- Client sends request without a payment token
- Server returns 402 with
payment-required header (base64-encoded JSON with plan info)
- Client acquires x402 token via
payments.x402.getX402AccessToken(planId, agentId, { delegationConfig }) — requires a delegation (either an existing delegationId or spendingLimitCents + durationSecs to auto-create one)
- Client retries with
payment-signature header containing the token
- Server verifies → executes → settles (burns credits), returns response with
payment-response header
Framework Decision Tree
Choose the integration that matches your stack:
| Framework | Language | Reference | Key Import |
|---|
| Express.js | TypeScript/JS | references/express-integration.md | paymentMiddleware from @nevermined-io/payments/express |
| FastAPI | Python | references/fastapi-integration.md | PaymentMiddleware from payments_py.x402.fastapi |
| Strands Agent | Python | references/strands-integration.md | @requires_payment from payments_py.x402.strands |
| MCP Server | TypeScript | references/mcp-paywall.md | payments.mcp.start() / payments.mcp.registerTool() |
| Google A2A | TS / Python | references/a2a-integration.md | payments.a2a.start() / payments.a2a.buildPaymentAgentCard() |
| Any HTTP | Any | references/x402-protocol.md | Manual verify/settle via facilitator API |
| Client-side | TS / Python | references/client-integration.md | payments.x402.getX402AccessToken() with delegationConfig |
SDK Quick Reference
TypeScript (@nevermined-io/payments)
const payments = Payments.getInstance({ nvmApiKey, environment })
const priceConfig =
payments.plans.getERC20PriceConfig(10_000_000n, USDC_ADDRESS, builderAddress)
const creditsConfig =
payments.plans.getFixedCreditsConfig(100n, 1n)
const { agentId, planId } = await payments.agents.registerAgentAndPlan(
agentMetadata, agentApi, planMetadata, priceConfig, creditsConfig
)
await payments.plans.orderPlan(planId)
const planBalance = await payments.plans.getPlanBalance(planId)
console.log(`Credits remaining: ${planBalance.balance}`)
const { accessToken } = await payments.x402.getX402AccessToken(planId, agentId, {
delegationConfig: { spendingLimitCents: 100, durationSecs: 3600 }
})
const verification = await payments.facilitator.verifyPermissions({
paymentRequired, x402AccessToken: token, maxAmount: BigInt(credits)
})
const settlement = await payments.facilitator.settlePermissions({
paymentRequired, x402AccessToken: token, maxAmount: BigInt(creditsUsed)
})
import { buildPaymentRequired } from '@nevermined-io/payments'
import { paymentMiddleware, X402_HEADERS } from '@nevermined-io/payments/express'
payments.mcp.registerTool(name, config, handler, { credits: 5n })
const { info, stop } = await payments.mcp.start({ port, agentId, serverName })
const agentCard = payments.a2a.buildPaymentAgentCard(baseCard, { paymentType, credits, planId, agentId })
const server = await payments.a2a.start({ port, basePath: '/a2a/', agentCard, executor })
const client = payments.a2a.getClient({ agentBaseUrl, agentId, planId })
await client.sendMessage("Hello", accessToken)
Python (payments-py)
from payments_py.x402 import DelegationConfig, X402TokenOptions
payments = Payments.get_instance(PaymentOptions(nvm_api_key=key, environment="sandbox"))
price_config = payments.plans.get_erc20_price_config(10_000_000, USDC_ADDRESS, builder_address)
credits_config = payments.plans.get_fixed_credits_config(100, 1)
result = payments.agents.register_agent_and_plan(
agent_metadata, agent_api, plan_metadata, price_config, credits_config
)
payments.plans.order_plan(plan_id)
plan_balance = payments.plans.get_plan_balance(plan_id)
print(f"Credits remaining: {plan_balance.balance}")
token_res = payments.x402.get_x402_access_token(
plan_id, agent_id,
token_options=X402TokenOptions(
delegation_config=DelegationConfig(spending_limit_cents=100, duration_secs=3600)
)
)
verification = payments.facilitator.verify_permissions(
payment_required=pr, x402_access_token=token, max_amount=str(credits)
)
settlement = payments.facilitator.settle_permissions(
payment_required=pr, x402_access_token=token, max_amount=str(credits_used)
)
from payments_py.x402.helpers import build_payment_required
from payments_py.x402.fastapi import PaymentMiddleware
from payments_py.x402.strands import requires_payment
from payments_py.a2a.agent_card import build_payment_agent_card
from payments_py.a2a.server import PaymentsA2AServer
agent_card = build_payment_agent_card(base_card, { ... })
server = PaymentsA2AServer.start(agent_card=agent_card, executor=executor, payments_service=payments, port=3005)
client = payments.a2a.get_client(agent_base_url=url, agent_id=agent_id, plan_id=plan_id)
x402 Payment Headers
All x402 v2 integrations use these three HTTP headers:
| Header | Direction | Description |
|---|
payment-signature | Client → Server | x402 access token |
payment-required | Server → Client (402) | Base64-encoded JSON with plan requirements |
payment-response | Server → Client (200) | Base64-encoded JSON settlement receipt |
The payment-required payload structure:
{
"x402Version": 2,
"accepts": [{
"scheme": "nvm:erc4337",
"network": "eip155:84532",
"planId": "<plan-id>",
"extra": { "agentId": "<agent-id>" }
}]
}
Supported x402 schemes
| Scheme | Network field | Settlement |
|---|
nvm:erc4337 | CAIP-2 chain ID (e.g. eip155:84532 Base Sepolia, eip155:8453 Base Mainnet) | Crypto stablecoins (USDC / EURC) via account-abstraction delegation |
nvm:card-delegation | Fiat provider (stripe or braintree) | Card-on-file via Stripe or Braintree delegation |
The SDK auto-resolves the scheme from the plan's priceConfig metadata. You only need to pass scheme explicitly if you want to override it.
Payment Plan Types
Nevermined supports several plan types:
- Credits-based: prepaid balance, deducted per request (most common for APIs). Use
getFixedCreditsConfig or getDynamicCreditsConfig.
- Time-based: access for a fixed duration (e.g., 30 days unlimited). Use
getExpirableDurationConfig.
- Pay-as-you-go (PAYG): one credit granted and burned per purchase — clients re-purchase before each call. Use
getPayAsYouGoPriceConfig + getPayAsYouGoCreditsConfig.
- Trial: free limited access, one-time claim per user. Use
getFreePriceConfig.
- Hybrid: combine fixed credits with a time expiry by passing
accessLimit: 'time' and an expirable duration config.
Each plan can be priced in crypto (getERC20PriceConfig, getEURCPriceConfig, getNativeTokenPriceConfig) or fiat (getFiatPriceConfig — Stripe/Braintree). The selected price helper determines the x402 scheme used at runtime.
For fiat plans, the active provider is selected per plan via the fiatPaymentProvider metadata field ('stripe' or 'braintree'). Sellers using Braintree must connect a Braintree merchant account with at least one child merchant account in the plan's currency — see braintree-onboarding for the seller-side setup and card-enrollment for the buyer-side flow.
See references/payment-plans.md for plan registration code.
Common Patterns
Express.js — Fixed credits per route
import { paymentMiddleware } from '@nevermined-io/payments/express'
app.use(paymentMiddleware(payments, {
'POST /ask': { planId: PLAN_ID, credits: 1 },
'POST /generate': { planId: PLAN_ID, credits: 5 }
}))
FastAPI — Fixed credits per route
from payments_py.x402.fastapi import PaymentMiddleware
app.add_middleware(
PaymentMiddleware,
payments=payments,
routes={
"POST /ask": {"plan_id": PLAN_ID, "credits": 1},
"POST /generate": {"plan_id": PLAN_ID, "credits": 5}
}
)
Express.js — Dynamic credits based on response
paymentMiddleware(payments, {
'POST /generate': {
planId: PLAN_ID,
credits: (req, res) => {
const tokens = res.locals.tokenCount || 100
return Math.ceil(tokens / 100)
}
}
})
FastAPI — Dynamic credits based on request
async def calculate_credits(request: Request) -> int:
body = await request.json()
max_tokens = body.get("max_tokens", 100)
return max(1, max_tokens // 100)
app.add_middleware(
PaymentMiddleware,
payments=payments,
routes={"POST /generate": {"plan_id": PLAN_ID, "credits": calculate_credits}}
)
MCP Server — Register tool with paywall
payments.mcp.registerTool(
"weather.today",
{ title: "Today's Weather", inputSchema: z.object({ city: z.string() }) },
async (args, extra, context) => ({
content: [{ type: "text", text: `Weather in ${args.city}: Sunny, 25C` }]
}),
{ credits: 5n }
)
const { info, stop } = await payments.mcp.start({
port: 3000,
agentId: process.env.NVM_AGENT_ID!,
serverName: "my-server"
})
Strands Agent — Decorator-based payment
from strands import Agent, tool
from payments_py.x402.strands import requires_payment
@tool(context=True)
@requires_payment(payments=payments, plan_id=PLAN_ID, credits=1)
def analyze_data(query: str, tool_context=None) -> dict:
return {"status": "success", "content": [{"text": f"Analysis: {query}"}]}
agent = Agent(tools=[analyze_data])
Google A2A — Agent server with payment extension
TypeScript
const agentCard = payments.a2a.buildPaymentAgentCard(baseAgentCard, {
paymentType: "dynamic",
credits: 1,
planId: process.env.NVM_PLAN_ID!,
agentId: process.env.NVM_AGENT_ID!,
})
const server = await payments.a2a.start({
port: 3005,
basePath: '/a2a/',
agentCard,
executor: new MyExecutor(),
})
Python
from payments_py.a2a.agent_card import build_payment_agent_card
from payments_py.a2a.server import PaymentsA2AServer
agent_card = build_payment_agent_card(base_agent_card, {
"paymentType": "dynamic",
"credits": 1,
"planId": os.environ["NVM_PLAN_ID"],
"agentId": os.environ["NVM_AGENT_ID"],
})
server = PaymentsA2AServer.start(
agent_card=agent_card,
executor=MyExecutor(),
payments_service=payments,
port=3005,
base_path="/a2a/",
)
Google A2A — Client sending a paid task
const client = payments.a2a.getClient({
agentBaseUrl: 'http://localhost:3005/a2a/',
agentId: AGENT_ID,
planId: PLAN_ID,
})
const { accessToken } = await payments.x402.getX402AccessToken(PLAN_ID, AGENT_ID, {
delegationConfig: { spendingLimitCents: 100, durationSecs: 3600 }
})
const response = await client.sendMessage("Analyze this data", accessToken)
Gathering Developer Information Upfront
When a developer asks you to integrate Nevermined payments, gather ALL required information in a single question before generating code. This avoids multiple back-and-forth interactions.
Ask the developer once for:
- Framework: Express.js, FastAPI, MCP server, Strands agent, Google A2A, or generic HTTP?
- Routes to protect: Which endpoints need payment protection and how many credits each? (e.g.,
POST /chat = 1 credit, POST /generate = 5 credits)
- Pricing model: Fixed credits per request, or dynamic pricing based on request/response parameters?
- Nevermined API Key: Do they already have an
NVM_API_KEY? If not, direct them to Get Your API Key
- Plan ID: Do they already have a
NVM_PLAN_ID? If not, do they need a registration script too?
- Environment:
sandbox (testing) or live (production)?
If they need plan registration, also ask:
- Plan name and description: e.g., "Starter Plan — 100 API requests"
- Pricing: How much in USDC? (e.g., 10 USDC for 100 credits)
- Credits per plan: Total credits included (e.g., 100)
- Builder wallet address (
BUILDER_ADDRESS): The wallet that receives payments
Example combined prompt to offer the developer:
I need to set up Nevermined payments. Here's my info:
- Framework: Express.js
- Routes: POST /chat (1 credit), POST /summarize (3 credits)
- I need a registration script too
- Plan: "Starter Plan", 100 credits for 10 USDC
- Environment: sandbox
- My API key is in the NVM_API_KEY env var
- My wallet: 0x1234...
With this information, generate both the registration script and the payment-protected server in a single response.
Agent and Plan Registration
Using the SDK (Recommended)
Register your agent and plan programmatically — see references/payment-plans.md for complete code.
const { agentId, planId } = await payments.agents.registerAgentAndPlan(
{ name: 'My Agent', description: 'AI service', tags: ['ai'], dateCreated: new Date() },
{ endpoints: [{ POST: 'https://your-api.com/query' }] },
{ name: 'Starter Plan', description: '100 requests for $10', dateCreated: new Date() },
payments.plans.getERC20PriceConfig(10_000_000n, USDC_ADDRESS, process.env.BUILDER_ADDRESS!),
payments.plans.getFixedCreditsConfig(100n, 1n)
)
from payments_py.plans import get_erc20_price_config, get_fixed_credits_config
result = payments.agents.register_agent_and_plan(
agent_metadata={'name': 'My Agent', 'description': 'AI service', 'tags': ['ai']},
agent_api={'endpoints': [{'POST': 'https://your-api.com/query'}]},
plan_metadata={'name': 'Starter Plan', 'description': '100 requests for $10'},
price_config=get_erc20_price_config(10_000_000, USDC_ADDRESS, os.environ['BUILDER_ADDRESS']),
credits_config=get_fixed_credits_config(100, 1)
)
Using the Nevermined App (No-Code)
- Go to nevermined.app and sign in
- Click "My agents" → register a new agent with metadata and endpoints
- Create a payment plan: set pricing, credits, and duration
- Link the plan to your agent and publish
- Copy the
agentId and planId for your .env file
Using the CLI
npm install -g @nevermined-io/cli
nvm config init --api-key "$NVM_API_KEY" --environment sandbox
PRICE=$(nvm plans get-erc20-price-config \
--amount 10000000 \
--token-address 0x036CbD53842c5426634e7929541eC2318f3dCF7e \
--receiver $BUILDER_ADDRESS \
--format json)
CREDITS=$(nvm plans get-fixed-credits-config \
--credits-granted 100 \
--credits-per-request 1 \
--format json)
nvm agents register-agent-and-plan \
--agent-metadata '{"name":"My Agent","description":"AI service"}' \
--agent-api '{"endpoints":[{"POST":"https://your-api.com/query"}]}' \
--plan-metadata '{"name":"Starter Plan","description":"100 requests"}' \
--price-config "$PRICE" \
--credits-config "$CREDITS"
nvm plans get-plans
nvm plans order-plan $PLAN_ID
nvm x402token get-x402-access-token $PLAN_ID \
--agent-id $AGENT_ID \
--spending-limit-cents 10000 \
--delegation-duration-secs 604800
curl -X POST http://localhost:3000/chat \
-H "Content-Type: application/json" \
-H "payment-signature: $TOKEN" \
-d '{"message": "Hello"}'
Troubleshooting
| Symptom | Cause | Fix |
|---|
| HTTP 402 returned | No payment-signature header or invalid/expired token | Generate a fresh token via getX402AccessToken with delegationConfig |
MCP error -32003 | Payment Required — no token, invalid token, or insufficient credits | Check subscriber has purchased plan and has credits remaining |
MCP error -32002 | Server misconfiguration | Verify NVM_API_KEY, NVM_PLAN_ID, and NVM_AGENT_ID are set correctly |
verification.isValid is false | Token expired, wrong plan, or insufficient credits | Re-order the plan or generate a new token |
| Credits not deducting | Settlement not called after request | Ensure you call settlePermissions after processing (middleware does this automatically) |
payment-required header missing | Server not returning 402 properly | Use buildPaymentRequired() helper or framework middleware |
Additional Resources