Payment Plans give AI Builders the ability to control how and when users can use an AI Agent or service. They are entirely controlled and managed by the AI Builder that creates them with no interference from Nevermined.Nevermined Payment Plans enable time-based or request-based gating of an AI Agent.
Provides user access with per-request pricing. Builders can manage the cost per request to access their AI service. This is done by setting the price to purchase a bundle of credits and the number of credits redeemed for each request (as configured during Plan creation). Each time a request is made, user credits are validated and redeemed. If the user does not have enough credits, they will be prompted to purchase more and denied access until they do so.
TypeScript
Python
// This is the USDC ERC20 address in the test network (sandbox)const USDC_ERC20_TESTING = '0x036CbD53842c5426634e7929541eC2318f3dCF7e'const planMetadata = { name: 'My Credits Plan', tags: ['test']}// The price is 20 USDC (20_000_000) in the sandbox networkconst priceConfig = payments.plans.getERC20PriceConfig(20_000_000n, USDC_ERC20_TESTING, builderAddress)// The subscriber receives 100 credits upon purchasing the planconst creditsConfig = payments.plans.getFixedCreditsConfig(100n)// Register the planconst { planId } = await payments.plans.registerCreditsPlan( planMetadata, priceConfig, creditsConfig)
# This is the USDC ERC20 address in the test network (sandbox)USDC_ERC20_TESTING = "0x036CbD53842c5426634e7929541eC2318f3dCF7e"# Plan metadataplan_metadata = PlanMetadata( name="My Credits Plan", tags=["test"])# The price is 20 USDC (20_000_000) in the sandbox networkprice_config = get_erc20_price_config(20_000_000, USDC_ERC20_TESTING, builder_address)# The subscriber receives 100 credits upon purchasing the plancredits_config = get_fixed_credits_config(100)# Register the planresponse = payments_builder.plans.register_credits_plan( plan_metadata, price_config, credits_config)plan_id = response.get("planId")
Provides user access on a time-gating basis. Builders can set the time period that a user is allowed access to the AI (e.g. 1 year, 1 month, 1 hour, etc.). When a user makes their first request, the corresponding access credit is redeemed, granting access for the designated period. Once the time period has elapsed, the user will no longer have access and will need to redeem another credit for continued access.
TypeScript
Python
// The price is 5 USDC (5_000_000) in the sandbox networkconst priceConfig = payments.plans.getERC20PriceConfig(5_000_000n, ERC20_ADDRESS, builderAddress)// The plan is valid for 1 dayconst oneDayPlanConfig = payments.plans.getExpirableDurationConfig(ONE_DAY_DURATION)// Register the planconst { planId } = await payments.plans.registerTimePlan( planMetadata, priceConfig, oneDayPlanConfig)
# The price is 5 USDC (5_000_000) in the sandbox networkprice_config = get_erc20_price_config(5_000_000, ERC20_ADDRESS, builder_address)# The plan is valid for 1 dayone_day_plan_config = get_expirable_duration_config(ONE_DAY_DURATION)# Register the planresponse = payments_builder.plans.register_time_plan( plan_metadata, price_config, one_day_plan_config)plan_id = response.get("planId")
A Trial Plan is a special type of Payment Plan that allows users to try out an AI Agent for a limited time (typically for free). A Trial Plan can only be obtained once by each user.There are two types of trial plans:
Perfect for giving users free access for a limited time period:
TypeScript
Python
import { getFreePriceConfig, getExpirableDurationConfig, ONE_DAY_DURATION } from '@nevermined-io/payments'const trialPlanMetadata = { name: 'Try it for one day before you buy it'}// The price is freeconst freeConfig = getFreePriceConfig()// The plan is valid for 1 dayconst oneDayPlanConfig = payments.plans.getExpirableDurationConfig(ONE_DAY_DURATION)// Register the time-based trial planconst { planId } = await payments.plans.registerTimeTrialPlan( trialPlanMetadata, freeConfig, oneDayPlanConfig)
from payments_py.plans import get_free_price_config, get_expirable_duration_config, ONE_DAY_DURATION# Plan metadata for the trial plantrial_plan_metadata = PlanMetadata( name="Try it for one day before you buy it")# The price is freefree_config = get_free_price_config()# The plan is valid for 1 dayone_day_plan_config = get_expirable_duration_config(ONE_DAY_DURATION)# Register the time-based trial planresponse = payments_builder.plans.register_time_trial_plan( trial_plan_metadata, free_config, one_day_plan_config)plan_id = response.get("planId")
Pay As You Go plan is a type of payment plan that allows users to pay for each request they make to an AI Agent without having to purchase a bundle of credits upfront.
TypeScript
Python
import { Payments, getPayAsYouGoCreditsConfig,} from '@nevermined-io/payments'// USDC on the sandbox networkconst USDC_ERC20_TESTING = '0x036CbD53842c5426634e7929541eC2318f3dCF7e'const payments = Payments.getInstance({ nvmApiKey: process.env.NVM_API_KEY, environment: 'sandbox',})const planMetadata = { name: 'My PAYG Plan', description: 'Pay per request',}// The SDK fetches the PAYG template address from the API info endpointconst priceConfig = await payments.plans.getPayAsYouGoPriceConfig( 100n, // amount per request (token minor units) '0x9dDD02D4E111ab5cE47511987B2500fcB56252c6', // receiver USDC_ERC20_TESTING, // ERC20 token)// Credits config is required for validation but not used to mint creditsconst creditsConfig = getPayAsYouGoCreditsConfig()const { planId } = await payments.plans.registerPlan( planMetadata, priceConfig, creditsConfig,)
from payments_py import Paymentsfrom payments_py.common.types import PaymentOptions, PlanMetadatafrom payments_py.plans import get_pay_as_you_go_credits_configUSDC_ERC20_TESTING = "0x036CbD53842c5426634e7929541eC2318f3dCF7e"payments = Payments( PaymentOptions( nvm_api_key="YOUR_NVM_API_KEY", environment="sandbox", ))plan_metadata = PlanMetadata( name="My PAYG Plan", description="Pay per request",)# SDK fetches PAYG template address from the API info endpointprice_config = payments.plans.get_pay_as_you_go_price_config( amount=100, receiver="0x9dDD02D4E111ab5cE47511987B2500fcB56252c6", token_address=USDC_ERC20_TESTING,)# Credits config is required for validation but credits are not minted upfrontcredits_config = get_pay_as_you_go_credits_config()response = payments.plans.register_credits_plan( plan_metadata, price_config, credits_config,)plan_id = response.get("planId")
To register an AI Agent you only need a name, a description, and at least one Payment Plan to associate with it. The API attributes that describe how requests authenticate are configured in agentApi — most builders only need authType plus a credential.
Before registering an AI Agent, you need to have a Payment Plan created.
TypeScript
Python
const agentMetadata: AgentMetadata = { name: 'E2E Payments Agent', tags: ['test'], dateCreated: new Date(), description: 'Description for the E2E Payments Agent'}// Minimal API config — your Payments library middleware handles// per-route gating. See "Additional Security" below to opt into a// platform-enforced route allowlist.const agentApi = { authType: 'bearer', token: process.env.AGENT_BEARER_TOKEN,}const paymentPlans = [creditsPlanId, expirablePlanId]const { agentId } = await payments.agents.registerAgent( agentMetadata, agentApi, paymentPlans)
from datetime import datetimefrom payments_py.common.types import AgentMetadata, AgentAPIAttributes, AuthTypeagent_metadata = AgentMetadata( name="E2E Payments Agent", tags=["test"], date_created=datetime.now().isoformat(), description="Description for the E2E Payments Agent",)import os# Minimal API config — your Payments library middleware handles# per-route gating. See "Additional Security" below to opt into a# platform-enforced route allowlist.agent_api = AgentAPIAttributes( auth_type=AuthType.BEARER, token=os.environ["AGENT_BEARER_TOKEN"],)payment_plans = [credits_plan_id, expirable_plan_id]response = payments_builder.agents.register_agent( agent_metadata, agent_api, payment_plans)agent_id = response.get("agentId")
If you want the Nevermined platform to enforce a route-level allowlist on top of your library middleware, provide endpoints (TypeScript and Python) and, for public routes, openEndpoints (TypeScript) or open_endpoints (Python). When set, only requests matching one of the configured entries are accepted during x402 verification; non-matching requests are rejected. You can also publish a discoverable agent definition by setting agentDefinitionUrl (TypeScript) or agent_definition_url (Python).
TypeScript
Python
// You can use wildcards (like :agentId) to match any string in the URL.// See https://github.com/pillarjs/path-to-regexp for supported syntax.const agentApi = { authType: 'bearer', token: process.env.AGENT_BEARER_TOKEN, endpoints: [ { POST: 'https://example.com/api/v1/agents/:agentId/tasks' }, { GET: 'https://example.com/api/v1/agents/:agentId/tasks/invoke' }, ], openEndpoints: ['https://example.com/api/v1/rest/docs-json'], agentDefinitionUrl: 'https://example.com/api/v1/openapi.json',}
Existing agents registered before April 2026 still have these fields populated and continue to enforce the allowlist as before. No migration is needed.
The fields below are part of the optional Additional Security allowlist described above — they only apply when you explicitly populate endpoints and/or openEndpoints (TypeScript) / open_endpoints (Python). For most builders integrating via the Payments library middleware, route-level gating is handled by your application code and these fields can be omitted entirely.
Protected Endpoints (endpoints): URLs that require a valid Payment Plan subscription. When present, x402 verify accepts only requests matching one of these entries.
Open Endpoints (openEndpoints / open_endpoints): URLs that are publicly accessible (e.g., documentation, health checks).
URL Patterns: Support wildcards for dynamic routing — see below.
We use path-to-regexp to define and validate the URL patterns of your agent endpoints. This allows dynamic routing via named parameters and wildcards. See the project documentation for full syntax and options: path-to-regexp.
Wildcard example:
https://example.com/api/v1/agents/*path
Matches one or more segments after agents/ and captures them into the path array.