TypeScript SDK to interact with the Nevermined Payments Protocol
nevermined.io
The evolution of AI-native commerce is inevitable, but the infrastructure to support it is currently lacking. Today, AI agents require seamless, automated payment systems for individual transactions. As demand grows, these agents will scale into swarms, transacting and operating autonomously.
Existing solutions are designed for human use with physical money. This does not reflect the new reality, where AI Agents need to make and receive payments quickly and efficiently, without the limitations of traditional payment systems.
Nevermined provides a solution that seamlessly evolves from single-agent needs to complex AI economies, eliminating friction and supporting a fully autonomous, composable future for AI-driven commerce.
The Nevermined Payments Library is a TypeScript SDK that allows AI Builders and Subscribers to make AI Agents available for querying and use by other agents or humans. It is designed to be used alongside the Nevermined protocol, which provides a decentralized infrastructure for managing AI agents and their interactions.
The Payments Library enables:
[]
The library is designed for use in browser environments or as part of AI Agents:
# yarn
yarn add @nevermined-io/payments
# npm
npm install @nevermined-io/payments
Nevermined Payments integrates with the A2A protocol to authorize and charge per request between agents:
/.well-known/agent.json
.capabilities.streaming: true
for message/stream
and tasks/resubscribe
.Authorization: Bearer ...
), not in the JSON‑RPC payload.metadata.creditsUsed
; Nevermined validates and burns credits accordingly.Add a payment extension under capabilities.extensions
carrying Nevermined metadata:
{
"capabilities": {
"streaming": true,
"pushNotifications": true,
"extensions": [
{
"uri": "urn:nevermined:payment",
"description": "Dynamic cost per request",
"required": false,
"params": {
"paymentType": "dynamic",
"credits": 1,
"planId": "<planId>",
"agentId": "<agentId>"
}
}
]
},
"url": "https://your-agent.example.com/a2a/"
}
Important notes:
url
must match exactly the URL registered in Nevermined for the agent/plan.metadata.creditsUsed
with the consumed cost.To use the Nevermined Payments Library, you need to get your Nevermined API key. You can get yours freely from the Nevermined App.
sandbox
, live
.staging_sandbox
, staging_live
.Pick the environment that matches where your agent and plans are registered. The agent card url
must belong to that environment.
This is a browser only method. Here we have an example using react. For a full example please refer to payments-nextjs-example
import { useEffect } from "react";
import { Payments } from "@nevermined-io/payments";
export default function Home() {
const payments = new Payments({
returnUrl: "http://localhost:8080",
environment: "staging",
});
const onLogin = () => {
payments.connect();
};
useEffect(() => {
payments.init();
}, []);
return (
<main>
<div>
<button onClick={onLogin}>Login</button>
</div>
</main>
);
}
The init()
method should be called immediately after the app returns the user to returnUrl
.
import { Payments } from "@nevermined-io/payments";
const payments = Payments.getInstance({
nvmApiKey,
environment: 'testing' as EnvironmentName,
})
Once the app is initialized we can create a payment plan:
const planMetadata: PlanMetadata = {
name: 'E2E test Payments Plan',
}
const priceConfig = payments.plans.getERC20PriceConfig(20n, ERC20_ADDRESS, builderAddress)
const creditsConfig = payments.plans.getFixedCreditsConfig(100n)
const { planId } = await payments.plans.registerCreditsPlan(planMetadata, priceConfig, creditsConfig)
Or register a plan limited by time:
const priceConfig = payments.plans.getERC20PriceConfig(50n, ERC20_ADDRESS, builderAddress)
const expirablePlanConfig = payments.plans.getExpirableDurationConfig(payments.plans.ONE_DAY_DURATION) // 1 day
const response = await payments.plans.registerTimePlan(planMetadata, priceConfig, expirablePlanConfig)
// Some metadata about the agent
const agentMetadata = {
name: 'E2E Payments Agent',
tags: ['test'],
}
// The API that the agent will expose
const agentApi = {
endpoints: [
{ 'POST': `https://example.com/api/v1/agents/:agentId/tasks` },
{ 'GET': `https://example.com/api/v1/agents/:agentId/tasks/invoke` }
]}
// This is the list of payment plans that the agent will accept
const paymentPlans = [ creditsPlanId, expirablePlanId ]
const result = await payments.agents.registerAgent(agentMetadata, agentApi, paymentPlans)
const orderResult = await payments.plans.orderPlan(creditsPlanId)
And get the balabce of the purchased plan:
const balance = await payments.plans.getPlanBalance(creditsPlanId)
console.log(`Balance: ${balance}`)
Once the user has purchased a plan, they can query the agent:
const params = await payments.agents.getAgentAccessToken(creditsPlanId, agentId)
const agentHTTPOptions = {
method: 'POST',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
Authorization: `Bearer ${params.accessToken}`
},
}
const response = await fetch(new URL(agentURL), agentHTTPOptions)
Authorization: Bearer <token>
, protected by Nevermined Payments Engine and receive JSON‑RPC results or errors.Nevermined integration to protect MCP handlers and burn credits.
import { Payments } from '@nevermined-io/payments'
// 1) Create Payments on the server
const payments = Payments.getInstance({ nvmApiKey, environment })
// 2) Configure the MCP wrapper
payments.mcp.configure({ agentId: process.env.NVM_AGENT_ID!, serverName: 'my-mcp' })
// 3) Wrap your handlers (works for both high-level and low-level servers)
// Tool
const toolHandler = async ({ city }: { city: string }) => ({
content: [{ type: 'text', text: `Weather for ${city}` }],
})
const protectedTool = payments.mcp.withPaywall(toolHandler, {
kind: 'tool',
name: 'weather.today',
credits: 2n, // or (ctx) => bigint
})
// High-level: server.registerTool('weather.today', config, protectedTool)
// Low-level: const tools = new Map([[ 'weather.today', protectedTool ]])
// Alternative registration:
const { registerResource } = payments.mcp.attach(server)
const resourceHandler = async (uri: URL, vars: Record<string, string | string[]>) => ({
contents: [{ uri: uri.href, mimeType: 'application/json', text: JSON.stringify({ city: vars.city }) }],
})
registerResource('weather-today', template, config, resourceHandler, { credits: 1n })
Notes:
extra
object with headers.Authorization
(e.g., extra = { headers: req.headers }
).onRedeemError: 'propagate'
)Authorization
, calls Nevermined startProcessingRequest
, executes the handler, and calls redeemCreditsFromRequest
.credits
can be a bigint
or (ctx) => bigint
with { args, result, request }
.name
builds the logical URL mcp://{serverName}/{kind}/{name}
.Copyright 2025 Nevermined AG
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.