> ## Documentation Index
> Fetch the complete documentation index at: https://docs.nevermined.app/llms.txt
> Use this file to discover all available pages before exploring further.

# Register Plans & Agents

> Register AI agents and create payment plans on Nevermined. Configure pricing, credits, and payment currency with the SDK or visually in the Web App.

You can create Payment Plans and register AI Agents manually or programmatically:

<Note>
  **This page is for sellers/builders** — publishing an agent so others can pay for it. If you only want to **buy or use** an existing agent, you don't need to register anything or create a plan: see [Buy & Call a Paid Agent](/docs/getting-started/ai-agent-purchase).
</Note>

<CardGroup cols={2}>
  <Card title="Nevermined App" icon="calculator">
    Go to the [Nevermined App](https://nevermined.app) and click on "My agents" or "My pricing plans" to create Payment Plans and register your AI Agents.
  </Card>

  <Card title="Payments Libraries" icon="calendar">
    Use the Payments Libraries to programmatically create Payment Plans and register AI Agents.
  </Card>
</CardGroup>

<Note>
  In this guide, we will focus on how to register AI Agents and create Payment Plans using the Payments Libraries.
</Note>

Once you have a Payments instance, you can start creating Plans and registering AI Agents.

## Creating a Payment Plan

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.

## Creating Credit-Based Plans

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.

<Tabs>
  <Tab title="TypeScript">
    ```typescript theme={null}
    // 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 network
    const priceConfig = payments.plans.getERC20PriceConfig(20_000_000n, USDC_ERC20_TESTING, builderAddress)
    // The subscriber receives 100 credits upon purchasing the plan
    const creditsConfig = payments.plans.getFixedCreditsConfig(100n)
    // Register the plan
    const { planId } = await payments.plans.registerCreditsPlan(
      planMetadata, 
      priceConfig, 
      creditsConfig
    )
    ```
  </Tab>

  <Tab title="Python">
    ```python theme={null}
    # This is the USDC ERC20 address in the test network (sandbox)
    USDC_ERC20_TESTING = "0x036CbD53842c5426634e7929541eC2318f3dCF7e"

    # Plan metadata
    plan_metadata = PlanMetadata(
        name="My Credits Plan",
        tags=["test"]
    )

    # The price is 20 USDC (20_000_000) in the sandbox network
    price_config = get_erc20_price_config(20_000_000, USDC_ERC20_TESTING, builder_address)
    # The subscriber receives 100 credits upon purchasing the plan
    credits_config = get_fixed_credits_config(100)

    # Register the plan
    response = payments_builder.plans.register_credits_plan(
        plan_metadata,
        price_config,
        credits_config
    )
    plan_id = response.get("planId")
    ```
  </Tab>
</Tabs>

### Creating a Credits Plan in EUR/EURC

You can also create plans priced in EUR (fiat) or EURC (Euro stablecoin):

<Tabs>
  <Tab title="TypeScript">
    ```typescript theme={null}
    import { Currency, EURC_TOKEN_ADDRESS_TESTNET } from '@nevermined-io/payments'

    // EUR fiat plan — amount in 6-decimal units (€29.00), NOT cents
    const eurPriceConfig = payments.plans.getFiatPriceConfig(29_000_000n, builderAddress, Currency.EUR)
    const { planId: eurPlanId } = await payments.plans.registerCreditsPlan(
      { name: 'EUR Credits Plan' },
      eurPriceConfig,
      payments.plans.getFixedCreditsConfig(100n)
    )

    // EURC crypto plan (Euro stablecoin)
    const eurcPriceConfig = payments.plans.getEURCPriceConfig(
      20_000_000n,                  // 20 EURC (6 decimals)
      builderAddress,
      EURC_TOKEN_ADDRESS_TESTNET    // Testnet address for sandbox
    )
    const { planId: eurcPlanId } = await payments.plans.registerCreditsPlan(
      { name: 'EURC Credits Plan' },
      eurcPriceConfig,
      payments.plans.getFixedCreditsConfig(100n)
    )
    ```
  </Tab>

  <Tab title="Python">
    ```python theme={null}
    from payments_py.common.types import Currency, EURC_TOKEN_ADDRESS_TESTNET
    from payments_py.plans import PlanMetadata, get_fiat_price_config, get_eurc_price_config, get_fixed_credits_config

    # EUR fiat plan — amount in 6-decimal units (€29.00), NOT cents
    eur_price_config = get_fiat_price_config(29_000_000, builder_address, Currency.EUR)
    eur_plan = payments_builder.plans.register_credits_plan(
        PlanMetadata(name="EUR Credits Plan"),
        eur_price_config,
        get_fixed_credits_config(100)
    )

    # EURC crypto plan (Euro stablecoin)
    eurc_price_config = get_eurc_price_config(
        20_000_000,                    # 20 EURC (6 decimals)
        builder_address,
        EURC_TOKEN_ADDRESS_TESTNET     # Testnet address for sandbox
    )
    eurc_plan = payments_builder.plans.register_credits_plan(
        PlanMetadata(name="EURC Credits Plan"),
        eurc_price_config,
        get_fixed_credits_config(100)
    )
    ```
  </Tab>
</Tabs>

## Creating a Time-Based Plan

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.

<Tabs>
  <Tab title="TypeScript">
    ```typescript theme={null}
    // The price is 5 USDC (5_000_000) in the sandbox network
    const priceConfig = payments.plans.getERC20PriceConfig(5_000_000n, ERC20_ADDRESS, builderAddress)
    // The plan is valid for 1 day
    const oneDayPlanConfig = payments.plans.getExpirableDurationConfig(ONE_DAY_DURATION)
    // Register the plan
    const { planId } = await payments.plans.registerTimePlan(
      planMetadata, 
      priceConfig, 
      oneDayPlanConfig
    )
    ```
  </Tab>

  <Tab title="Python">
    ```python theme={null}
    # The price is 5 USDC (5_000_000) in the sandbox network
    price_config = get_erc20_price_config(5_000_000, ERC20_ADDRESS, builder_address)
    # The plan is valid for 1 day
    one_day_plan_config = get_expirable_duration_config(ONE_DAY_DURATION)
    # Register the plan
    response = payments_builder.plans.register_time_plan(
        plan_metadata,
        price_config,
        one_day_plan_config
    )
    plan_id = response.get("planId")
    ```
  </Tab>
</Tabs>

## Creating a Trial Plan

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:

### Credits-Based Trial Plan

Perfect for giving users a fixed number of free credits to test your service:

<Tabs>
  <Tab title="TypeScript">
    ```typescript theme={null}
    // Helper functions are accessed via payments.plans

    const trialPlanMetadata = {
      name: 'Free Trial - 10 Credits'
    }

    // The price is free
    const freeConfig = getFreePriceConfig()
    // Give 10 credits for free
    const trialCreditsConfig = getFixedCreditsConfig(10n)

    // Register the credits-based trial plan
    const { planId } = await payments.plans.registerCreditsTrialPlan(
      trialPlanMetadata,
      freeConfig,
      trialCreditsConfig
    )
    ```
  </Tab>

  <Tab title="Python">
    ```python theme={null}
    from payments_py.plans import get_free_price_config, get_fixed_credits_config

    trial_plan_metadata = PlanMetadata(
        name="Free Trial - 10 Credits"
    )

    # The price is free
    free_config = get_free_price_config()
    # Give 10 credits for free
    trial_credits_config = get_fixed_credits_config(10)

    # Register the credits-based trial plan
    response = payments_builder.plans.register_credits_trial_plan(
        trial_plan_metadata,
        free_config,
        trial_credits_config
    )
    plan_id = response.get("planId")
    ```
  </Tab>
</Tabs>

### Time-Based Trial Plan

Perfect for giving users free access for a limited time period:

<Tabs>
  <Tab title="TypeScript">
    ```typescript theme={null}
    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 free
    const freeConfig = getFreePriceConfig()
    // The plan is valid for 1 day
    const oneDayPlanConfig = payments.plans.getExpirableDurationConfig(ONE_DAY_DURATION)

    // Register the time-based trial plan
    const { planId } = await payments.plans.registerTimeTrialPlan(
      trialPlanMetadata,
      freeConfig,
      oneDayPlanConfig
    )
    ```
  </Tab>

  <Tab title="Python">
    ```python theme={null}
    from payments_py.plans import get_free_price_config, get_expirable_duration_config, ONE_DAY_DURATION

    # Plan metadata for the trial plan
    trial_plan_metadata = PlanMetadata(
        name="Try it for one day before you buy it"
    )

    # The price is free
    free_config = get_free_price_config()
    # The plan is valid for 1 day
    one_day_plan_config = get_expirable_duration_config(ONE_DAY_DURATION)

    # Register the time-based trial plan
    response = payments_builder.plans.register_time_trial_plan(
        trial_plan_metadata,
        free_config,
        one_day_plan_config
    )
    plan_id = response.get("planId")
    ```
  </Tab>
</Tabs>

## Creating a Pay As You Go Plan

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.

<Tabs>
  <Tab title="TypeScript">
    ```typescript theme={null}
    import {
      Payments,
      getPayAsYouGoCreditsConfig,
    } from '@nevermined-io/payments'

    // USDC on the sandbox network
    const 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 endpoint
    const 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 credits
    const creditsConfig = getPayAsYouGoCreditsConfig()

    const { planId } = await payments.plans.registerPlan(
      planMetadata,
      priceConfig,
      creditsConfig,
    )
    ```
  </Tab>

  <Tab title="Python">
    ```python theme={null}
    from payments_py import Payments
    from payments_py.common.types import PaymentOptions, PlanMetadata
    from payments_py.plans import get_pay_as_you_go_credits_config

    USDC_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 endpoint
    price_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 upfront
    credits_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")
    ```
  </Tab>
</Tabs>

## Registering an AI Agent

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.

<Note>
  Before registering an AI Agent, you need to have a Payment Plan created.
</Note>

<Tabs>
  <Tab title="TypeScript">
    ```typescript theme={null}
    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
    )
    ```
  </Tab>

  <Tab title="Python">
    ```python theme={null}
    from datetime import datetime
    from payments_py.common.types import AgentMetadata, AgentAPIAttributes, AuthType

    agent_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")
    ```
  </Tab>
</Tabs>

### Additional Security: Endpoint Allowlist (opt-in)

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).

<Tabs>
  <Tab title="TypeScript">
    ```typescript theme={null}
    // 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',
    }
    ```
  </Tab>

  <Tab title="Python">
    ```python theme={null}
    import os

    from payments_py.common.types import (
        AgentAPIAttributes,
        AuthType,
        Endpoint,
    )

    agent_api = AgentAPIAttributes(
        auth_type=AuthType.BEARER,
        token=os.environ["AGENT_BEARER_TOKEN"],
        endpoints=[
            Endpoint(verb="POST", url="https://example.com/api/v1/agents/:agentId/tasks"),
            Endpoint(verb="GET", url="https://example.com/api/v1/agents/:agentId/tasks/invoke"),
        ],
        open_endpoints=["https://example.com/api/v1/rest/docs-json"],
        agent_definition_url="https://example.com/api/v1/openapi.json",
    )
    ```
  </Tab>
</Tabs>

<Info>
  Existing agents registered before April 2026 still have these fields populated and continue to enforce the allowlist as before. No migration is needed.
</Info>

## Register an AI Agent and Payment Plan in One Step

<Note>
  This method allows you to create the plan and attach the agent to it in one step.
</Note>

**Note:** The `accessLimit` parameter is optional. If not specified, it is automatically inferred based on `creditsConfig.durationSecs`:

* `"credits"` if `durationSecs === 0n` (non-expirable plans)
* `"time"` if `durationSecs > 0n` (expirable plans)

You can explicitly set it if needed:

<Tabs>
  <Tab title="TypeScript">
    ```typescript theme={null}
    const agentMetadata = { 
      name: 'My AI Payments Agent', 
      tags: ['test2'], 
      description: 'Description for my AI Payments Agent' 
    }
    // Minimal config; opt into Additional Security as shown above.
    const agentApi = {
      authType: 'bearer',
      token: process.env.AGENT_BEARER_TOKEN,
    }

    const cryptoPriceConfig = getNativeTokenPriceConfig(500n, builderAddress)
    // Non expirable payment plan
    const nonExpirableConfig = getNonExpirableDurationConfig()

    const { agentId, planId } = await paymentsBuilder.agents.registerAgentAndPlan(
      agentMetadata,
      agentApi,
      planMetadata,
      cryptoPriceConfig,
      nonExpirableConfig,
      'credits' // Optional: accessLimit ('credits' or 'time'). Auto-inferred if not specified
    )
    ```
  </Tab>

  <Tab title="Python">
    ```python theme={null}
    import os

    from payments_py.common.types import AgentAPIAttributes, AuthType

    # Agent metadata and API definition
    agent_metadata = {
        "name": "My AI Payments Agent",
        "tags": ["test2"],
        "description": "Description for my AI Payments Agent"
    }
    # Minimal config; opt into Additional Security as shown above.
    agent_api = AgentAPIAttributes(
        auth_type=AuthType.BEARER,
        token=os.environ["AGENT_BEARER_TOKEN"],
    )

    # The price is 500 native tokens
    crypto_price_config = get_native_token_price_config(500, builder_address)
    # Non expirable payment plan
    non_expirable_config = get_non_expirable_duration_config()

    response = payments_builder.agents.register_agent_and_plan(
        agent_metadata,
        agent_api,
        plan_metadata,
        crypto_price_config,
        non_expirable_config,
        'credits'  # Optional: access_limit ('credits' or 'time'). Auto-inferred if not specified
    )
    agent_id = response['agentId']
    plan_id = response['planId']
    print('Plan created', response['planId'])
    print('Agent attached', response['agentId'])
    ```
  </Tab>
</Tabs>

## Key Concepts

### Endpoint Protection (opt-in)

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.

### URL Patterns (path-to-regexp)

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](https://github.com/pillarjs/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.

* Parameters example:

```
https://example.com/api/v1/agents/:agentId/tasks/:taskId
```

Captures `agentId` and `taskId` as named parameters.

### Payment Plan Types

<CardGroup cols={3}>
  <Card title="Credits-Based" icon="coins">
    Sets the price per-request. Users buy a bundle of credits that are redeemed against usage.
  </Card>

  <Card title="Time-Based" icon="clock">
    Users get unlimited access for a specific time period (hours, days, months).
  </Card>

  <Card title="Trial Plans" icon="gift">
    Free access for limited time or credits to let users test your service.
  </Card>

  <Card title="Pay As You Go" icon="dollar-sign">
    Pay for each request they make to an AI Agent without having to purchase a bundle of credits upfront.
  </Card>
</CardGroup>

### Best Practices

<AccordionGroup>
  <Accordion title="Plan Naming">
    Use descriptive names that clearly indicate what the plan offers (e.g., "Basic API Access - 1000 requests").
  </Accordion>

  <Accordion title="Pricing Strategy">
    Start with competitive pricing and adjust based on usage patterns and user feedback.
  </Accordion>

  <Accordion title="Endpoint Design">
    Group related functionality under the same payment plan to provide better value to subscribers.
  </Accordion>

  <Accordion title="Trial Plans">
    Always offer trial plans to reduce barriers to entry and increase conversion rates.
  </Accordion>
</AccordionGroup>

## Next Steps

Once you have registered your agents and plans, you can:

<CardGroup cols={2}>
  <Card title="Test Purchasing" icon="shopping-cart" href="/docs/development-guide/order-plans">
    Learn how users purchase your payment plans
  </Card>

  <Card title="Handle Requests" icon="server" href="/docs/development-guide/process-requests">
    Implement request validation in your AI agent
  </Card>
</CardGroup>
