Skill version: 0.5.2 | Last updated: 2026-09-25 | Canonical source (always latest): https://github.com/nevermined-io/docs/tree/main/skills/nevermined-payments
Use the latest version. This skill changes often. If you have an installed or cached copy, compare its Last updated date with the canonical source above and refresh it if older — an out-of-date copy can be missing whole flows. Unless a specific version is requested, work from the latest.
Verified against the live sandbox API (
https://api.sandbox.nevermined.app/api/v1/rest/docs-json); the cited SDK calls were checked against@nevermined-io/payments@1.13.0andpayments-py@1.18.0— install the latest release of each.
Nevermined provides financial rails for AI agents — real-time monetization, access control, and payments. This skill covers two modes, and most tasks fall cleanly into one:
ModeYou are…Lead interfaceUse when the goal is…🅐 Operate as an autonomous agentan agent acting on its own behalf at runtimeREST (works with no SDK install)buy a plan, enroll a card + delegation, get an API key, register a plan/agent, check credits (buyer) or revenue (seller)🅑 Add payments to your codea developer wiring payments into an agent so it can receive paymentsSDK (TypeScript / Python)protect Express/FastAPI/MCP/A2A/Strands endpoints behind a plan
If you are an autonomous agent that needs to pay, enroll, register, or report, start at Track A — Operate as an autonomous agent. If you are building a service that needs to charge callers, jump to Track B — Add payments to your code.
Nevermined uses the x402 protocol (HTTP 402 Payment Required). A buyer acquires an access token authorizing a spend, then settles it — which charges the payment method, mints, and burns credits. The same token can be sent to a protected agent in the payment-signature header; the agent verifies and settles for you.
Two payment schemes exist:
SchemePays withnetwork valuenvm:erc4337Crypto stablecoins (USDC / EURC) via account-abstraction delegationCAIP-2 chain id — eip155:84532 (sandbox / Base Sepolia), eip155:8453 (live / Base Mainnet)nvm:card-delegationA card on file via Stripe / Braintree / Visa delegationstripe, braintree, or visa
Three HTTP headers carry x402 data: payment-signature (client→server, the token), payment-required (server→client on 402, base64 JSON), payment-response (server→client on 200, base64 settlement receipt).
This is a REST runbook: every step (A1–A8 below) is a plain HTTPS call you can make with curl or any HTTP client — no SDK install required. Each flow ends with the equivalent SDK one-liner if you prefer typed calls.
Where the full detail lives. Every flow is documented inline below (A1–A8). The complete request/response bodies are in the reference files alongside this skill — read the matching one when you need exact payloads:
You need…ReadAPI keys, card enrollment + embedded session + delegation, payment methods, x402 buy/settle, buyer status — full REST bodiesreferences/autonomous-operations.md (card flow = §3, x402 buy = §4)Seller revenue / analytics queries (A7)references/seller-operations.mdOnboard your own customers (white-label, A8)references/customer-onboarding.mdPlan registration + the plan-type matrix (A6)references/payment-plans.mdSubscriber-side SDK patternsreferences/client-integration.md
Design principle — minimal human interaction. A human is needed for at most two one-time setup steps — often just one:
- Get your first API key (a human signs in once) — always required, and
- Enroll a card (a human enters card details in a browser — required by PCI) — only if you pay by card; the stablecoin path skips this entirely.
Everything else is fully programmatic and reusable: checking payment methods, creating delegations, purchasing, settling, registering plans/agents, and reading buyer/seller status. Store the API key and any
delegationIdand reuse them.
Pick the environment and use its exact base URL for every call. State it explicitly to yourself — do not infer it from anything else.
EnvironmentAPI base URLApp (human steps)Card enrollment UINetworkAPI key prefixsandbox (test money)https://api.sandbox.nevermined.app``https://nevermined.app``https://embed.nevermined.appBase Sepolia eip155:84532``sandbox:live (real money)https://api.live.nevermined.app``https://nevermined.app``https://embed.nevermined.appBase Mainnet eip155:8453``live:
Authorization: Bearer <NVM_API_KEY> on every call (a few read-only endpoints — e.g. GET /protocol/plans/{id} and GET /protocol/agents/{id}/plans — are public, but the header is harmless there).delegationId, and paymentMethodId arrive as query-string params on your 127.0.0.1 callback (see A1/A3). Your callback server must not log the request line, and you should keep the key in a secret store — query strings are the most-logged part of any request (access logs, shell history, process args).GET {API_BASE}/api/v1/rest/docs-json returns the OpenAPI JSON. Heads-up — it is not exhaustive: several agent-facing endpoints are served but deliberately omitted from docs-json, notably POST /embed/session (card enrollment), the delegation/* routes, and organizations/{orgId}/analytics/*. Don't conclude an endpoint doesn't exist because it's absent from the OpenAPI — use the exact paths documented in this skill directly. (To confirm one is live, send the request: a 401/ 400 means it exists; only 404 means it doesn't.)sandbox unless the human explicitly asks for live — live moves real money.Nevermined-Version: <MAJOR.MINOR> on every direct REST call so platform releases can't change the wire shape under you. Discover the supported range with GET {API_BASE}/api/v1/meta/versions (authenticated; returns current, floor, gatedVersions, and the pin of YOUR key) and default to its current. Without the header, requests use the key's stored pin (editable by the key owner in the dashboard). The SDKs send the header automatically ( LOCKED_API_VERSION). Never silently change a key's stored pin — pinning is the integration owner's deliberate decision. Changelog: https://nevermined.ai/docs/development-guide/api-changelogYou cannot mint your first key yourself — a human signs in once. Default flow: drive a one-time browser login and capture the key automatically (Option A). Host a 127.0.0.1 callback, print a single sign-in URL for the human to open, and read the key off the redirect. Do not ask the human to copy/paste a key or write it to a file unless Option A is genuinely impossible (no localhost callback) — then use Option B.
Option A — embedded login (the default; the key returns to you automatically). Host a tiny callback server on 127.0.0.1 (the login page only redirects to localhost/ 127.0.0.1 callbacks), then print this URL and ask your human to open it:
text
https://nevermined.app/auth/cli?callback_url=http://127.0.0.1:<port>/callback
After they sign in, the browser is redirected to http://127.0.0.1:<port>/callback?nvm_api_key=<api-key> — read nvm_api_key off that request. (Keys for sandbox start with sandbox; for live, live.)
Option B — manual paste (works anywhere). Ask your human to open nevermined.app, sign in, create an API Key (Settings → Global NVM API Keys → + New API Key), and paste it back. Or, once signed in, open https://nevermined.app/auth/cli with no callback_url to see the key on screen.
Store the key and reuse it. Never fabricate a key; the placeholder is sandbox:your-api-key. Full docs: https://nevermined.ai/docs/agents-guide/get-api-key
bash
curl -H "Authorization: Bearer $NVM_API_KEY" \
https://api.sandbox.nevermined.app/api/v1/payment-methods
# → [ { id, type, brand, last4, provider, status, ... } ]
sandbox it spends test USDC on Base Sepolia; see stablecoin payments for funding. Its id is your wallet/holder address (used in A5).status is capitalized ( "Active", "Revoked") and the erc4337 method's type is "crypto_wallet". (In A5, delegation cents fields like spendingLimitCents come back as strings, not numbers.)SDK: payments.delegation.listPaymentMethods() / payments.delegation.list_payment_methods().
Skip this entirely if you pay with stablecoins. To pay with a card, use the embedded browser flow — same shape as the API key in A1: host a 127.0.0.1 callback, print the card-setup URL for the human to open in a browser, they sign in and enter the card, and you capture paymentMethodId + delegationId from the redirect. Open to any agent with an API key (no organization required).
bash
# 1. Mint an embedded session (host a 127.0.0.1 callback first)
curl -X POST -H "Authorization: Bearer $NVM_API_KEY" -H "Content-Type: application/json" \
-d '{"returnUrl":"http://127.0.0.1:<port>/callback"}' \
https://api.sandbox.nevermined.app/api/v1/embed/session
# → { "sessionToken": "...", "userId": "...", "userWallet": "0x...", "expiresAt": "..." }
POST /api/v1/embed/sessionis served but not listed indocs-json(see A0) — call it directly; don't search the OpenAPI for it. It accepts any valid API key, takes only{ returnUrl }(alocalhost/127.0.0.1URL), and returns asessionToken.
text
https://embed.nevermined.app/cards/setup?sessionToken=<sessionToken>&returnUrl=http://127.0.0.1:<port>/callback&state=<random>&provider=stripe
returnUrl with paymentMethodId and delegationId as query params. Store the delegationId — a delegation authorizes you to spend within a fixed budget and time window, and you reuse it until it is spent or expires. To enforce a specific spending cap and duration (e.g. $50 over 30 days), create the delegation explicitly with POST /delegation/create (below), passing the callback's paymentMethodId as the providerPaymentMethodId field.Generate
stateas an unguessable random value and reject the callback unless the returnedstatematches the one you sent — it binds the response to your request (CSRF guard). And per A0, don't log the callback request line:paymentMethodId/delegationIdride in the query string.
Create a delegation explicitly. provider is one of stripe, braintree, visa (card) or erc4337 (stablecoin). provider, currency, spendingLimitCents, and durationSecs are required (no silent default for provider or currency; use currency: "usdc" for erc4337, "usd" for card providers).
bash
# Stablecoin (crypto) — no card, no human. Uses your default smart-account method.
curl -X POST -H "Authorization: Bearer $NVM_API_KEY" -H "Content-Type: application/json" \
-d '{"provider":"erc4337","spendingLimitCents":10000,"durationSecs":604800,"currency":"usdc"}' \
https://api.sandbox.nevermined.app/api/v1/delegation/create
# Card (Stripe). providerPaymentMethodId is the `id` returned by GET /payment-methods.
curl -X POST -H "Authorization: Bearer $NVM_API_KEY" -H "Content-Type: application/json" \
-d '{"provider":"stripe","providerPaymentMethodId":"pm_...","spendingLimitCents":10000,"durationSecs":604800,"currency":"usd"}' \
https://api.sandbox.nevermined.app/api/v1/delegation/create
# → { "delegationId": "...", "delegationToken": "..." }
SDK: payments.delegation.createDelegation({ provider: 'erc4337', spendingLimitCents, durationSecs, currency: 'usdc' }). provider and currency are required (no silent default); the delegation is plan-agnostic unless you pass planId.
Visa caveat.
delegation/createdoes acceptprovider: "visa", but only together with a browser-producedconsumerPrompt+assuranceDatafrom a Visa WebAuthn ceremony; omitting them is rejected withBCK.VISA.0014("requires consumerPrompt and assuranceData"). An autonomous agent can't generateassuranceData, so in practice have your human create the Visa delegation in the webapp and reuse itsdelegationId.
Full detail: the complete embedded card-enrollment handshake (session → card-setup redirect → delegationId), the localhost-callback rules, and every delegation/create field and response are in references/autonomous-operations.md §3.
Two calls: get an access token, then settle. x402 is the default buy flow for both rails — crypto and card work the same way, only scheme/ network differ. The facilitator charges the right method (on-chain against your delegation for crypto, the card for fiat), mints, and burns.
bash
# 1. Get an access token (authorizes the spend against your delegation)
curl -X POST -H "Authorization: Bearer $NVM_API_KEY" -H "Content-Type: application/json" \
-d '{
"accepted": { "scheme": "nvm:erc4337", "network": "eip155:84532", "planId": "<PLAN_ID>" },
"delegationConfig": { "delegationId": "<YOUR_DELEGATION_ID>" }
}' \
https://api.sandbox.nevermined.app/api/v1/x402/permissions
# → { "accessToken": "..." }
# 2. Settle — charges the method, mints, and burns; this receipt is your proof of purchase
curl -X POST -H "Authorization: Bearer $NVM_API_KEY" -H "Content-Type: application/json" \
-d '{
"paymentRequired": {
"x402Version": 2,
"resource": { "url": "<PLAN_OR_RESOURCE_URL>" },
"accepts": [ { "scheme": "nvm:erc4337", "network": "eip155:84532", "planId": "<PLAN_ID>", "extra": {} } ],
"extensions": {}
},
"x402AccessToken": "<accessToken>"
}' \
https://api.sandbox.nevermined.app/api/v1/x402/settle
# → { "success": true, "billingModel": "credits", "creditsRedeemed": "1", "remainingBalance": "999", "transaction": "0x...", "network": "eip155:84532" }
Pay with a card instead: set "scheme": "nvm:card-delegation" and "network": "stripe" (or braintree/ visa) in both accepted and accepts[0].
resource.url for a plan top-up = the plan's own URL, {API_BASE}/api/v1/protocol/plans/<PLAN_ID>.
Which scheme does a plan use? GET {API_BASE}/api/v1/protocol/plans/<PLAN_ID> (public) returns the plan's metadata and pricing so you can pick nvm:erc4337 vs nvm:card-delegation before paying. When buying from a protected agent, its 402 tells you instead.
Note the field rename: /permissions returns accessToken; pass that value as x402AccessToken in /settle and /verify.
Dry run first (optional): POST /api/v1/x402/verify with the same { paymentRequired, x402AccessToken } body → { "isValid": true }.
Proof of purchase depends on billingModel — read it first, it is always in the response.
"credits": success: true and creditsRedeemed > 0 (and, for crypto, an on-chain transaction)."pay-as-you-go": success: true and a non-empty orderTx (fiat rails) or transaction (crypto rails). These plans hold no credit balance, so creditsRedeemed and remainingBalance are always the string "0" even on a charge that succeeded — creditsRedeemed > 0 there reports a real charge as a decline, and on a card rail that invites a retry of a payment that already went through."0" is truthy while Number("0") > 0 is false, so two plausible checks disagree.billingModel at all? The deployment predates the discriminator — apply the credits rule, never pay-as-you-go.Card budget caveat: a card settle may not immediately move the delegation's amountSpentCents/ remainingBudgetCents — use the settle receipt + the A5 plan balance as the source of truth for card spend, not the delegation budget.
Calling a protected agent directly (the common case): just send the access token as the payment-signature header to the agent's endpoint — the agent's own 402 response is your paymentRequired, and the agent verifies + settles for you. You only call /settle yourself when topping up a plan with no protected endpoint to hit.
A dedicated
orderPlan/POST /protocol/plans/{id}/orderendpoint exists for an explicit, upfront stablecoin purchase, but x402 above is the default for both rails — use/orderonly when specifically requested.
SDK shortcut for step 1:
typescript
const { accessToken } = await payments.x402.getX402AccessToken(planId, agentId, {
delegationConfig: { delegationId } // create the delegation first via createDelegation, then pass its delegationId
})
python
res = payments.x402.get_x402_access_token(plan_id, agent_id,
token_options=X402TokenOptions(delegation_config=DelegationConfig(delegation_id=delegation_id)))
Full crypto + card walkthroughs with every field: references/autonomous-operations.md. Subscriber-side SDK patterns: references/client-integration.md.
You query a plan you hold by its <PLAN_ID>. There is no "list every plan I've purchased" endpoint, so retain the plan IDs you buy — each /x402/settle receipt identifies the plan, and the plan URL embeds the id. ( GET /protocol/plans lists plans you published as a seller, not ones you bought.)
bash
# Credits left on a plan you hold. YOUR_ADDRESS = your wallet: the `id`/address of your
# erc4337 payment method from GET /payment-methods (crypto), or the `userWallet` from POST /embed/session.
curl -H "Authorization: Bearer $NVM_API_KEY" \
https://api.sandbox.nevermined.app/api/v1/protocol/plans/<PLAN_ID>/balance/<YOUR_ADDRESS>
# → { planId, planName, planType, isSubscriber, balance, pricePerCredit, ... }
# Your delegations and remaining budget
curl -H "Authorization: Bearer $NVM_API_KEY" \
https://api.sandbox.nevermined.app/api/v1/delegation
# → { totalResults, delegations: [ { delegationId, status, spendingLimitCents, amountSpentCents, remainingBudgetCents, expiresAt } ] }
# `status` is "Active" | "Expired" | "Exhausted" — flag a delegation when status != "Active", or remainingBudgetCents is at/near 0, or expiresAt is near.
# Caveat: a CARD delegation's budget may not reflect a card settle immediately (amountSpentCents can stay 0) — for cards, treat the settle receipt + plan balance as the spend source of truth, not the delegation budget.
# A delegation's individual charges
curl -H "Authorization: Bearer $NVM_API_KEY" \
https://api.sandbox.nevermined.app/api/v1/delegation/<DELEGATION_ID>/transactions
SDK: payments.plans.getPlanBalance(planId) ( PlanBalance.balance is a bigint in TS / int in Python). The creditsRedeemed/ remainingBalance you get back from /settle (or the decoded payment-response header) is also a live proof of your balance after a purchase — on a credits plan. On a pay-as-you-go plan both read "0" regardless of what was charged; there is no balance to prove.
Registration is the one flow where the SDK is the recommended path: the price/credits configs are low-level on-chain structures (amounts, receivers, token addresses, redemption type, nonce) that the SDK helpers build for you.
typescript
const { agentId, planId } = await payments.agents.registerAgentAndPlan(
{ name: 'Weather Agent', description: 'Forecasts on demand', tags: ['weather'], dateCreated: new Date() },
{ endpoints: [{ POST: 'https://your-api.com/query' }] }, // optional; omit for an open agent
{ name: 'Starter Plan', description: '100 requests for $10', dateCreated: new Date() },
payments.plans.getFiatPriceConfig(10_000_000n, BUILDER_ADDRESS, 'USD'), // $10.00 — fiat is 6-decimal units, NOT cents. Or getERC20PriceConfig(...) for crypto
payments.plans.getFixedCreditsConfig(100n, 1n)
)
Price helpers: getERC20PriceConfig/ getEURCPriceConfig (crypto), getFiatPriceConfig (card). Credits helpers: getFixedCreditsConfig (prepaid), getExpirableDurationConfig (time-based), getPayAsYouGoCreditsConfig (per-call). The raw REST endpoints exist ( POST /api/v1/protocol/plans, /api/v1/protocol/agents, /api/v1/protocol/agents/plans) but expect the fully-formed priceConfig/ creditsConfig objects — use the SDK helpers to produce them. Full plan-type matrix and helper reference: references/payment-plans.md.
Organization analytics (require an active Premium org tier). Discover your orgId from your own records — every item in GET /protocol/plans and /protocol/agents carries .orgId + .organizationName; take the most common non-null .orgId across your published items (it's the org-... id, also in your …/organizations/<orgId>/agentic-instructions.md). Only call analytics with an id matching ^org-[0-9a-f-]+$. Failure modes to handle (fall back to the any-tier building blocks below on any of them):
403 BCK.AUTH.0004 ("Organisation admin privileges required");403 BCK.ORGANIZATIONS.0022;200 of all-zeros — never report that as real revenue; if you have published plans but analytics returns zeros, treat it as a failure.bash
B=https://api.sandbox.nevermined.app/api/v1/organizations/<ORG_ID>/analytics
curl -H "Authorization: Bearer $NVM_API_KEY" "$B/revenue?from=2026-03-20T00:00:00Z&to=2026-06-18T00:00:00Z"
# → { items: [ { agentId, agentName, totalRevenue, transactionCount } ], totalRevenue }
curl -H "Authorization: Bearer $NVM_API_KEY" "$B/mrr"
# → { mrr, activeSubscriptions }
curl -H "Authorization: Bearer $NVM_API_KEY" "$B/usage?from=...&to=..."
# → { items: [ { planId, planName, creditsBurned, uniqueUsers } ] }
curl -H "Authorization: Bearer $NVM_API_KEY" "$B/customers?limit=20"
# → { items: [ { customerId, userId, totalSpent, firstSeenAt, lastActiveAt } ], totalCustomers }
Reading the analytics rows: they're labelled
agentId/agentNamebut are grouped by plan;totalRevenue/totalSpentare stringified integers in 6-decimal token units (divide by 1,000,000 for USD), whilecreditsBurnedis a plain count.mrris legitimately0when sales were one-off credit purchases rather than recurring subscriptions.
Any-tier building blocks (no Premium required) — list what you've published and inspect each:
bash
curl -H "Authorization: Bearer $NVM_API_KEY" https://api.sandbox.nevermined.app/api/v1/protocol/plans # your plans
curl -H "Authorization: Bearer $NVM_API_KEY" https://api.sandbox.nevermined.app/api/v1/protocol/agents # your agents
curl -H "Authorization: Bearer $NVM_API_KEY" https://api.sandbox.nevermined.app/api/v1/protocol/agents/<AGENT_ID>/plans # plans on an agent
These return { total, page, offset, plans|agents: [ … ] }, but each item is the full record, not a flat summary: read the name from metadata.main.name and price/type from registry / metadata (the id is the plan/agent id). The flat { planName, planType, pricePerCredit } shape is only returned by the balance endpoint in A5, not by these list endpoints.
For per-request usage and cost observability (Helicone), see references/seller-operations.md, which details every seller query and the response shapes.
If you operate an organization, provision Nevermined accounts for your customers from your backend — no member seat, recorded in your Customers CRM, and returning a scoped key you use to pay for your agents on their behalf. One endpoint, distinguished by as: 'customer':
bash
curl -s -XPOST -H "Authorization: Bearer $ORG_ADMIN_API_KEY" -H "Content-Type: application/json" \
-d '{"email":"customer@example.com","as":"customer"}' \
https://api.sandbox.nevermined.app/api/v1/organizations/account
# New / returning customer → 201, walletResult.nvmApiKey (+ userId, userWallet, isCustomer, customerRecorded) — the USABLE key
# Email owned by a non-customer account → 202, walletResult.consentRequired=true (consent email sent; no key or identity disclosed)
SDK: payments.organizations.onboardCustomer(email) (TS) / payments.organizations.onboard_customer(email) (Python). The key is scoped to purchase + redeem only (not register/mint), short-lived (~30d), and revocable — use it to buy access (A4) and check credits (A5) on the customer's behalf. Full flow, the three provenance outcomes, and SDK code: references/customer-onboarding.md.
If your goal is to make your agent charge its callers (not to buy from others), that is Track B below — it shows how to gate Express/FastAPI/MCP/A2A/Strands endpoints behind a plan with verifyPermissions / settlePermissions or framework middleware.
Use this track to wire Nevermined into an agent or API so it can receive payments. This is SDK-first (TypeScript / Python).
All SDK, REST, and CLI calls require an NVM_API_KEY (see A1 for how to obtain one). Set it as an environment variable:
bash
export NVM_API_KEY="sandbox:your-api-key"
If the developer has no NVM_API_KEY yet, point them to A1 before generating code that needs it. Use sandbox:your-api-key as the placeholder in generated code — a realistic-looking fake key gets mistaken for a real one.
VariableRequiredDescriptionNVM_API_KEYYesYour Nevermined API key — see Get Your API KeyNVM_ENVIRONMENTYessandbox for testing, live for productionNVM_PLAN_IDYesThe plan ID from registrationNVM_AGENT_IDSometimesRequired for plans with multiple agents; optional (informational) for MCP serversBUILDER_ADDRESSFor registrationWallet address to receive payments
.env Template#bash
# Required
NVM_API_KEY=sandbox:your-api-key
NVM_ENVIRONMENT=sandbox
NVM_PLAN_ID=your-plan-id-here
# Required for multi-agent plans (optional for MCP servers)
NVM_AGENT_ID=your-agent-id-here
# Required for registration
BUILDER_ADDRESS=0xYourWalletAddress
package.json must include "type": "module" for the @nevermined-io/payments/express subpath import to work.pip install payments-py[fastapi] — the [fastapi] extra is required for the middleware.bash
npm install @nevermined-io/payments
typescript
import { Payments } from '@nevermined-io/payments'
const payments = Payments.getInstance({
nvmApiKey: process.env.NVM_API_KEY!,
environment: 'sandbox'
})
bash
pip install payments-py
python
import os
from payments_py import Payments, PaymentOptions
payments = Payments.get_instance(
PaymentOptions(
nvm_api_key=os.environ["NVM_API_KEY"],
environment="sandbox"
)
)
Every Nevermined payment integration follows this 5-step pattern:
payment-required header (base64-encoded JSON with plan info)payments.x402.getX402AccessToken(planId, agentId, { delegationConfig: { delegationId } }) — create the delegation first with createDelegation ( provider + currency required), then pass its delegationId (inline create-on-the-fly is deprecated)payment-signature header containing the tokenpayment-response headerChoose the integration that matches your stack:
FrameworkLanguageReferenceKey ImportExpress.jsTypeScript/JSreferences/express-integration.md``paymentMiddleware from @nevermined-io/payments/expressFastAPIPythonreferences/fastapi-integration.md``PaymentMiddleware from payments_py.x402.fastapiStrands AgentPythonreferences/strands-integration.md``@requires_payment from payments_py.x402.strandsLangChain / LangGraphTS / Pythonreferences/langchain-integration.md``@requires_payment from payments_py.x402.langchain / requiresPayment from @nevermined-io/payments/langchainMCP ServerTS / Pythonreferences/mcp-paywall.md (TypeScript examples; Python has payments.mcp.register_tool() / start())payments.mcp.start() / payments.mcp.registerTool()Google A2ATS / Pythonreferences/a2a-integration.md``payments.a2a.start() / Payments.a2a.buildPaymentAgentCard() (static)Any HTTPAnyreferences/x402-protocol.mdManual verify/settle via facilitator APIClient-sideTS / Pythonreferences/client-integration.md``payments.x402.getX402AccessToken() with delegationConfig
@nevermined-io/payments)#typescript
// Initialize
const payments = Payments.getInstance({ nvmApiKey, environment })
// Build price + credits configs (pick one helper per axis)
const priceConfig =
payments.plans.getERC20PriceConfig(10_000_000n, USDC_ADDRESS, builderAddress)
// or getEURCPriceConfig / getNativeTokenPriceConfig / getFreePriceConfig
// or getFiatPriceConfig(amount, builderAddress, 'USD') for Stripe/Braintree
// or await getPayAsYouGoPriceConfig(amount, builderAddress, tokenAddress?)
const creditsConfig =
payments.plans.getFixedCreditsConfig(100n, 1n)
// or getDynamicCreditsConfig / getExpirableDurationConfig
// or getPayAsYouGoCreditsConfig() for PAYG plans
// Register agent + plan
const { agentId, planId } = await payments.agents.registerAgentAndPlan(
agentMetadata, agentApi, planMetadata, priceConfig, creditsConfig
)
// Subscriber: order plan and get token
await payments.plans.orderPlan(planId)
const planBalance = await payments.plans.getPlanBalance(planId)
console.log(`Credits remaining: ${planBalance.balance}`) // PlanBalance.balance is bigint
// Create the delegation first (provider + currency required), then request the token by delegationId.
const delegation = await payments.delegation.createDelegation({
provider: 'erc4337', spendingLimitCents: 100, durationSecs: 3600, currency: 'usdc'
})
const { accessToken } = await payments.x402.getX402AccessToken(planId, agentId, {
delegationConfig: { delegationId: delegation.delegationId }
})
// Server: verify and settle
const verification = await payments.facilitator.verifyPermissions({
paymentRequired, x402AccessToken: token, maxAmount: BigInt(credits)
})
const settlement = await payments.facilitator.settlePermissions({
paymentRequired, x402AccessToken: token, maxAmount: BigInt(creditsUsed)
})
// Helpers
import { buildPaymentRequired } from '@nevermined-io/payments'
import { paymentMiddleware, X402_HEADERS } from '@nevermined-io/payments/express'
// MCP server
payments.mcp.registerTool(name, config, handler, { credits: 5n })
const { info, stop } = await payments.mcp.start({ port, planId, serverName }) // planId required; agentId optional
// A2A server
const agentCard = Payments.a2a.buildPaymentAgentCard(baseCard, { paymentType, credits, planId, agentId }) // static, on the class
const server = await payments.a2a.start({ port, basePath: '/a2a/', agentCard, executor })
// A2A client
const client = await payments.a2a.getClient({ agentBaseUrl, agentId, planId, delegationConfig: { delegationId } })
// sendA2AMessage mints the x402 token from delegationConfig and carries it in band
await client.sendA2AMessage({ message: { kind: 'message', role: 'user', messageId: crypto.randomUUID(), parts: [{ kind: 'text', text: 'Hello' }] } })
payments-py)#python
import asyncio
from payments_py.x402 import CreateDelegationPayload, DelegationConfig, X402TokenOptions
# Initialize
payments = Payments.get_instance(PaymentOptions(nvm_api_key=key, environment="sandbox"))
# Build price + credits configs (helpers exist on payments.plans and as module funcs)
price_config = payments.plans.get_erc20_price_config(10_000_000, USDC_ADDRESS, builder_address)
# or get_eurc_price_config / get_native_token_price_config / get_free_price_config
# or get_fiat_price_config(amount, builder_address, "USD") for Stripe/Braintree
# or payments.plans.get_pay_as_you_go_price_config(...) (sync; uses cached contract address)
credits_config = payments.plans.get_fixed_credits_config(100, 1)
# Register agent + plan
result = payments.agents.register_agent_and_plan(
agent_metadata, agent_api, plan_metadata, price_config, credits_config
)
# Subscriber: order plan and get token
payments.plans.order_plan(plan_id)
plan_balance = payments.plans.get_plan_balance(plan_id)
print(f"Credits remaining: {plan_balance.balance}") # PlanBalance.balance is int
# Create the delegation first (provider + currency required), then request the token by delegation_id.
delegation = payments.delegation.create_delegation(
CreateDelegationPayload(
provider="erc4337", spending_limit_cents=100, duration_secs=3600, currency="usdc"
)
)
token_res = payments.x402.get_x402_access_token(
plan_id, agent_id,
token_options=X402TokenOptions(
delegation_config=DelegationConfig(delegation_id=delegation.delegation_id)
)
)
# Server: verify and settle
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)
)
# Helpers
from payments_py.x402.helpers import build_payment_required
from payments_py.x402.fastapi import PaymentMiddleware
from payments_py.x402.strands import requires_payment
# A2A server
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)
# A2A client
# payments.a2a is a dict of helpers; the client mints the token from delegation_config
client = payments.a2a["get_client"](
agent_base_url=url, agent_id=agent_id, plan_id=plan_id,
delegation_config=DelegationConfig(delegation_id=delegation_id),
)
result = asyncio.run(client.send_message({"message": {"kind": "message", "role": "user", "messageId": "1", "parts": [{"kind": "text", "text": "Hello"}]}})) # or `await` inside async code
HTTP integrations (Express, FastAPI, generic HTTP) use these three headers. MCP and A2A carry the same payloads in band instead — MCP in the request/result _meta ( x402/payment, x402/payment-response), A2A in the message metadata — see their reference files.
HeaderDirectionDescriptionpayment-signatureClient → Serverx402 access tokenpayment-requiredServer → Client (402)Base64-encoded JSON with plan requirementspayment-responseServer → Client (200)Base64-encoded JSON settlement receipt
The payment-required payload structure:
json
{
"x402Version": 2,
"resource": { "url": "/api/endpoint" },
"accepts": [{
"scheme": "nvm:erc4337",
"network": "eip155:84532",
"planId": "<plan-id>",
"extra": { "agentId": "<agent-id>" }
}],
"extensions": {}
}
SchemeNetwork fieldSettlementnvm:erc4337CAIP-2 chain ID (e.g. eip155:84532 Base Sepolia, eip155:8453 Base Mainnet)Crypto stablecoins (USDC / EURC) via account-abstraction delegationnvm:card-delegationFiat provider ( stripe, braintree, or visa)Card-on-file via Stripe / Braintree / Visa Agentic Token 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.
Nevermined supports several plan types:
getFixedCreditsConfig or getDynamicCreditsConfig.getExpirableDurationConfig.getPayAsYouGoPriceConfig + getPayAsYouGoCreditsConfig.getFreePriceConfig.accessLimit: 'time' and an expirable duration config.Each plan can be priced in crypto ( getERC20PriceConfig, getEURCPriceConfig, getNativeTokenPriceConfig) or fiat ( getFiatPriceConfig — Stripe / Braintree / Visa Trusted Agent). 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', 'braintree', or 'visa'). Sellers using Braintree must connect a Braintree merchant account with at least one child merchant account in the plan's currency. Sellers offering Visa Trusted Agent plans must complete Stripe Connect onboarding (Visa delegations settle through Stripe Connect) — see Braintree onboarding for the Braintree seller setup and card enrollment for the buyer-side flow.
Visa caveat for SDK builders. Visa delegation creation is browser-only — it requires consumerPrompt + assuranceData produced by an in-browser WebAuthn ceremony embedded by Visa VTS. The SDK can consume an existing Visa delegation by passing its delegationId to DelegationConfig, but calling createDelegation / create_delegation with provider: 'visa' is rejected by the backend ( BCK.VISA.0014). For any SDK code path that needs a Visa delegation, instruct the user to create it in the Nevermined webapp and pass the resulting ID back to the agent.
See references/payment-plans.md for plan registration code.
Per-framework snippets — fixed and dynamic credits per route, paywalled MCP tools, the Strands decorator, A2A server and client — live in each framework's reference file (see the Framework Decision Tree above).
An integration needs the following. Read the project first (framework, routes, .env) and ask the developer, in one message, only for what you can't determine there:
POST /chat = 1 credit, POST /generate = 5 credits)NVM_API_KEY exists; if not, direct them to A1NVM_PLAN_ID exists; if not, whether they also want a registration scriptsandbox (testing) or live (production)For plan registration, also: plan name and description, price (e.g. 10 USDC for 100 credits), credits per plan, and the builder wallet address ( BUILDER_ADDRESS) that receives payments.
SDK (recommended): registerAgentAndPlan / register_agent_and_plan as shown in A6; full TypeScript and Python code in references/payment-plans.md.
No-code: sign in at nevermined.app → My agents, register the agent, create and link a plan, publish, and copy the agentId and planId into your .env.
bash
# 1. Install CLI
npm install -g @nevermined-io/cli
# 2. Configure (use sandbox for testing)
nevermined config init --api-key "$NVM_API_KEY" --environment sandbox
# 3. Build the helper-shaped configs and register
# The --price-config / --credits-config flags expect the JSON shape
# produced by Plans.getERC20PriceConfig and Plans.getFixedCreditsConfig —
# the helper subcommands below emit exactly that shape with --format json.
PRICE=$(nevermined plans get-erc20-price-config \
--amount 10000000 \
--token-address 0x036CbD53842c5426634e7929541eC2318f3dCF7e \
--receiver $BUILDER_ADDRESS \
--format json)
CREDITS=$(nevermined plans get-fixed-credits-config \
--credits-granted 100 \
--credits-per-request 1 \
--format json)
nevermined 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"
# 4. List your plans
nevermined plans get-plans
# 5. As a subscriber: order a plan and get an x402 token
# For fiat plans, pass --payment-type fiat (defaults to crypto).
nevermined plans order-plan $PLAN_ID
nevermined x402token get-x402-access-token $PLAN_ID \
--agent-id $AGENT_ID \
--spending-limit-cents 10000 \
--delegation-duration-secs 604800
# 6. Test against your running server
curl -X POST http://localhost:3000/chat \
-H "Content-Type: application/json" \
-H "payment-signature: $TOKEN" \
-d '{"message": "Hello"}'
SymptomCauseFixHTTP 402 returnedNo payment-signature header or invalid/expired tokenGenerate a fresh token via getX402AccessToken with delegationConfig``401 BCK.AUTH.0002 on a REST callMissing/expired API keySend Authorization: Bearer $NVM_API_KEY; mint a key per A1403 on analytics — BCK.ORGANIZATIONS.0022 (not Premium) or BCK.AUTH.0004 (not an admin of that org)Wrong tier, not your org, or a malformed orgId (which instead returns a silent 200-of-zeros)Discover the real orgId from .orgId on your plan/agent records; use the any-tier building blocks in A7, or upgrade the orgBCK.VISA.0014 creating a delegationprovider:"visa" sent without the browser-produced consumerPrompt + assuranceDataAn agent can't produce assuranceData — create the Visa delegation in the webapp; reuse the delegationId``BCK.X402.0002 Plan not foundWrong planId or wrong environmentVerify the plan ID and that you are calling the matching sandbox/ live base URLMCP tool result with isError: true and a PaymentRequired object in structuredContent (resources/prompts: a JSON-RPC error)Payment Required — no token, invalid token, insufficient credits, or settlement failed after the callCheck subscriber has purchased plan and has credits remainingMCP error -32002Server misconfigurationVerify NVM_API_KEY, NVM_PLAN_ID, and NVM_AGENT_ID are set correctlyverification.isValid is falseToken expired/invalid, wrong plan, plan not linked to the agent, or insufficient creditsRegenerate the token; if it persists, verify the plan is associated with the agent and that credits remain (don't just loop on token regeneration)Credits not deductingSettlement not called after requestEnsure you call settlePermissions after processing (middleware does this automatically)payment-required header missingServer not returning 402 properlyUse buildPaymentRequired() helper or framework middleware
GET {API_BASE}/api/v1/rest/docs-json (OpenAPI JSON)https://nevermined.ai/docs/mcp — search Nevermined docs from any MCP client@nevermined-io/payments on npmpayments-py on PyPI