Skip to content

Payments Class Reference

The main entry point for the Nevermined Payments Python SDK.

Payments

Payments

Payments(
    options: PaymentOptions,
    is_browser_instance: bool = False,
)

Bases: BasePaymentsAPI

Main class that interacts with the Nevermined payments API. Use Payments.get_instance for server-side usage.

The library provides methods to manage AI Agents, Plans & process AI Agent Requests.

Each of these functionalities is encapsulated in its own API class: - plans: Manages AI Plans, including registration and ordering and retrieving plan details. - agents: Handles AI Agents, including registration of AI Agents and access token generation. - requests: Manages requests received by AI Agents, including validation and tracking. - facilitator: Handles X402 permission verification and settlement for AI Agents acting as facilitators.

Initialize the Payments class.

PARAMETER DESCRIPTION
options

The initialization options

TYPE: PaymentOptions

is_browser_instance

Whether this is a browser instance (default False)

TYPE: bool DEFAULT: False

Source code in payments_py/payments.py
def __init__(self, options: PaymentOptions, is_browser_instance: bool = False):
    """
    Initialize the Payments class.

    Args:
        options: The initialization options
        is_browser_instance: Whether this is a browser instance (default False)
    """
    super().__init__(options)
    self.is_browser_instance = is_browser_instance
    self._initialize_api(options)

get_instance classmethod

get_instance(options: PaymentOptions) -> Payments

Get an instance of the Payments class for server-side usage.

PARAMETER DESCRIPTION
options

The options to initialize the payments class

TYPE: PaymentOptions

RETURNS DESCRIPTION
Payments

An instance of Payments

RAISES DESCRIPTION
PaymentsError

If nvm_api_key is missing

Source code in payments_py/payments.py
@classmethod
def get_instance(cls, options: PaymentOptions) -> "Payments":
    """
    Get an instance of the Payments class for server-side usage.

    Args:
        options: The options to initialize the payments class

    Returns:
        An instance of Payments

    Raises:
        PaymentsError: If nvm_api_key is missing
    """
    if not options.nvm_api_key:
        raise PaymentsError.unauthorized("Nevermined API Key is required")
    return cls(options, False)

get_browser_instance classmethod

get_browser_instance(options: PaymentOptions) -> Payments

Get an instance of the Payments class for browser usage.

PARAMETER DESCRIPTION
options

The options to initialize the payments class

TYPE: PaymentOptions

RETURNS DESCRIPTION
Payments

An instance of Payments

RAISES DESCRIPTION
PaymentsError

If return_url is missing

Source code in payments_py/payments.py
@classmethod
def get_browser_instance(cls, options: PaymentOptions) -> "Payments":
    """
    Get an instance of the Payments class for browser usage.

    Args:
        options: The options to initialize the payments class

    Returns:
        An instance of Payments

    Raises:
        PaymentsError: If return_url is missing
    """
    if not options.return_url:
        raise PaymentsError.validation("return_url is required")
    return cls(options, True)

Plans API

PlansAPI

PlansAPI(options: PaymentOptions)

Bases: BasePaymentsAPI

The PlansAPI class provides methods to register and interact with payment plans on Nevermined.

Initialize the PlansAPI class.

PARAMETER DESCRIPTION
options

The options to initialize the payments class

TYPE: PaymentOptions

Source code in payments_py/api/plans_api.py
def __init__(self, options: PaymentOptions):
    """
    Initialize the PlansAPI class.

    Args:
        options: The options to initialize the payments class
    """
    super().__init__(options)
    self.contracts_api = ContractsAPI(options)

get_instance classmethod

get_instance(options: PaymentOptions) -> PlansAPI

Get a singleton instance of the PlansAPI class.

PARAMETER DESCRIPTION
options

The options to initialize the payments class

TYPE: PaymentOptions

RETURNS DESCRIPTION
PlansAPI

The instance of the PlansAPI class

Source code in payments_py/api/plans_api.py
@classmethod
def get_instance(cls, options: PaymentOptions) -> "PlansAPI":
    """
    Get a singleton instance of the PlansAPI class.

    Args:
        options: The options to initialize the payments class

    Returns:
        The instance of the PlansAPI class
    """
    return cls(options)

register_plan

register_plan(
    plan_metadata: PlanMetadata,
    price_config: PlanPriceConfig,
    credits_config: PlanCreditsConfig,
    nonce: Optional[int] = None,
    access_limit: Optional[
        Literal["credits", "time"]
    ] = None,
) -> Dict[str, str]

Allows an AI Builder to create a Payment Plan on Nevermined in a flexible manner. A Nevermined Credits Plan limits access based on plan usage. With them, AI Builders control the number of requests that can be made to an agent or service. Every time a user accesses any resource associated with the Payment Plan, the usage consumes from a capped amount of credits. When the user consumes all the credits, the plan automatically expires and the user needs to top up to continue using the service.

PARAMETER DESCRIPTION
plan_metadata

Plan metadata

TYPE: PlanMetadata

price_config

Plan price configuration

TYPE: PlanPriceConfig

credits_config

Plan credits configuration

TYPE: PlanCreditsConfig

nonce

Optional nonce for the transaction

TYPE: Optional[int] DEFAULT: None

RETURNS DESCRIPTION
Dict[str, str]

The unique identifier of the plan (Plan ID) of the newly created plan

RAISES DESCRIPTION
PaymentsError

If registration fails

Source code in payments_py/api/plans_api.py
def register_plan(
    self,
    plan_metadata: PlanMetadata,
    price_config: PlanPriceConfig,
    credits_config: PlanCreditsConfig,
    nonce: Optional[int] = None,
    access_limit: Optional[
        Literal["credits", "time"]
    ] = None,  # 'credits' or 'time'
) -> Dict[str, str]:
    """
    Allows an AI Builder to create a Payment Plan on Nevermined in a flexible manner.
    A Nevermined Credits Plan limits access based on plan usage.
    With them, AI Builders control the number of requests that can be made to an agent or service.
    Every time a user accesses any resource associated with the Payment Plan, the usage consumes from a capped amount of credits.
    When the user consumes all the credits, the plan automatically expires and the user needs to top up to continue using the service.

    Args:
        plan_metadata: Plan metadata
        price_config: Plan price configuration
        credits_config: Plan credits configuration
        nonce: Optional nonce for the transaction

    Returns:
        The unique identifier of the plan (Plan ID) of the newly created plan

    Raises:
        PaymentsError: If registration fails
    """
    if access_limit and access_limit not in ["credits", "time"]:
        raise PaymentsError.validation(
            "Invalid access limit",
            "accessLimit must be either 'credits' or 'time'",
        )
    if not access_limit:
        access_limit = "time" if credits_config.duration_secs > 0 else "credits"

    if nonce is None:
        nonce = get_random_big_int()

    body = {
        "metadataAttributes": self.pydantic_to_dict(plan_metadata),
        "priceConfig": self.pydantic_to_dict(price_config),
        "creditsConfig": self.pydantic_to_dict(credits_config),
        "nonce": nonce,
        "isTrialPlan": getattr(plan_metadata, "is_trial_plan", False),
        "accessLimit": access_limit,
    }

    options = self.get_backend_http_options("POST", body)
    url = f"{self.environment.backend}{API_URL_REGISTER_PLAN}"

    response = requests.post(url, **options)
    if not response.ok:
        raise PaymentsError.internal(
            f"Unable to register plan. {response.status_code} - {response.text}"
        )

    return response.json()

register_credits_plan

register_credits_plan(
    plan_metadata: PlanMetadata,
    price_config: PlanPriceConfig,
    credits_config: PlanCreditsConfig,
) -> Dict[str, str]

Allows an AI Builder to create a Payment Plan on Nevermined based on Credits. A Nevermined Credits Plan limits the access by the access/usage of the Plan. With them, AI Builders control the number of requests that can be made to an agent or service. Every time a user accesses any resource associated with the Payment Plan, the usage consumes from a capped amount of credits. When the user consumes all the credits, the plan automatically expires and the user needs to top up to continue using the service.

PARAMETER DESCRIPTION
plan_metadata

Plan metadata

TYPE: PlanMetadata

price_config

Plan price configuration

TYPE: PlanPriceConfig

credits_config

Plan credits configuration

TYPE: PlanCreditsConfig

RETURNS DESCRIPTION
Dict[str, str]

The unique identifier of the plan (Plan ID) of the newly created plan

RAISES DESCRIPTION
PaymentsError

If the credits configuration is invalid

Source code in payments_py/api/plans_api.py
def register_credits_plan(
    self,
    plan_metadata: PlanMetadata,
    price_config: PlanPriceConfig,
    credits_config: PlanCreditsConfig,
) -> Dict[str, str]:
    """
    Allows an AI Builder to create a Payment Plan on Nevermined based on Credits.
    A Nevermined Credits Plan limits the access by the access/usage of the Plan.
    With them, AI Builders control the number of requests that can be made to an agent or service.
    Every time a user accesses any resource associated with the Payment Plan, the usage consumes from a capped amount of credits.
    When the user consumes all the credits, the plan automatically expires and the user needs to top up to continue using the service.

    Args:
        plan_metadata: Plan metadata
        price_config: Plan price configuration
        credits_config: Plan credits configuration

    Returns:
        The unique identifier of the plan (Plan ID) of the newly created plan

    Raises:
        PaymentsError: If the credits configuration is invalid
    """

    if credits_config.min_amount > credits_config.max_amount:
        raise PaymentsError.validation(
            "The creditsConfig.minAmount can not be more than creditsConfig.maxAmount"
        )

    return self.register_plan(
        plan_metadata, price_config, credits_config, access_limit="credits"
    )

register_time_plan

register_time_plan(
    plan_metadata: PlanMetadata,
    price_config: PlanPriceConfig,
    credits_config: PlanCreditsConfig,
) -> Dict[str, str]

Allows an AI Builder to create a Payment Plan on Nevermined limited by duration. A Nevermined Credits Plan limits the access by the access/usage of the Plan. With them, AI Builders control the number of requests that can be made to an agent or service. Every time a user accesses any resource associated with the Payment Plan, the usage consumes from a capped amount of credits. When the user consumes all the credits, the plan automatically expires and the user needs to top up to continue using the service.

PARAMETER DESCRIPTION
plan_metadata

Plan metadata

TYPE: PlanMetadata

price_config

Plan price configuration

TYPE: PlanPriceConfig

credits_config

Plan credits configuration

TYPE: PlanCreditsConfig

RETURNS DESCRIPTION
Dict[str, str]

The unique identifier of the plan (Plan ID) of the newly created plan

RAISES DESCRIPTION
PaymentsError

If the credits configuration is invalid

Source code in payments_py/api/plans_api.py
def register_time_plan(
    self,
    plan_metadata: PlanMetadata,
    price_config: PlanPriceConfig,
    credits_config: PlanCreditsConfig,
) -> Dict[str, str]:
    """
    Allows an AI Builder to create a Payment Plan on Nevermined limited by duration.
    A Nevermined Credits Plan limits the access by the access/usage of the Plan.
    With them, AI Builders control the number of requests that can be made to an agent or service.
    Every time a user accesses any resource associated with the Payment Plan, the usage consumes from a capped amount of credits.
    When the user consumes all the credits, the plan automatically expires and the user needs to top up to continue using the service.

    Args:
        plan_metadata: Plan metadata
        price_config: Plan price configuration
        credits_config: Plan credits configuration

    Returns:
        The unique identifier of the plan (Plan ID) of the newly created plan

    Raises:
        PaymentsError: If the credits configuration is invalid
    """

    return self.register_plan(
        plan_metadata, price_config, credits_config, access_limit="time"
    )

register_credits_trial_plan

register_credits_trial_plan(
    plan_metadata: PlanMetadata,
    price_config: PlanPriceConfig,
    credits_config: PlanCreditsConfig,
) -> Dict[str, str]

Allows an AI Builder to create a Trial Payment Plan on Nevermined based on Credits. A Nevermined Trial Plan allow subscribers of that plan to test the Agents associated to it. A Trial plan is a plan that only can be purchased once by a user.

PARAMETER DESCRIPTION
plan_metadata

Plan metadata

TYPE: PlanMetadata

price_config

Plan price configuration

TYPE: PlanPriceConfig

credits_config

Plan credits configuration

TYPE: PlanCreditsConfig

RETURNS DESCRIPTION
Dict[str, str]

The unique identifier of the plan (Plan ID) of the newly created plan

Source code in payments_py/api/plans_api.py
def register_credits_trial_plan(
    self,
    plan_metadata: PlanMetadata,
    price_config: PlanPriceConfig,
    credits_config: PlanCreditsConfig,
) -> Dict[str, str]:
    """
    Allows an AI Builder to create a Trial Payment Plan on Nevermined based on Credits.
    A Nevermined Trial Plan allow subscribers of that plan to test the Agents associated to it.
    A Trial plan is a plan that only can be purchased once by a user.

    Args:
        plan_metadata: Plan metadata
        price_config: Plan price configuration
        credits_config: Plan credits configuration

    Returns:
        The unique identifier of the plan (Plan ID) of the newly created plan
    """
    plan_metadata.is_trial_plan = True
    return self.register_credits_plan(plan_metadata, price_config, credits_config)

register_time_trial_plan

register_time_trial_plan(
    plan_metadata: PlanMetadata,
    price_config: PlanPriceConfig,
    credits_config: PlanCreditsConfig,
) -> Dict[str, str]

Allows an AI Builder to create a Trial Payment Plan on Nevermined limited by duration. A Nevermined Trial Plan allow subscribers of that plan to test the Agents associated to it. A Trial plan is a plan that only can be purchased once by a user.

PARAMETER DESCRIPTION
plan_metadata

Plan metadata

TYPE: PlanMetadata

price_config

Plan price configuration

TYPE: PlanPriceConfig

credits_config

Plan credits configuration

TYPE: PlanCreditsConfig

RETURNS DESCRIPTION
Dict[str, str]

The unique identifier of the plan (Plan ID) of the newly created plan

Source code in payments_py/api/plans_api.py
def register_time_trial_plan(
    self,
    plan_metadata: PlanMetadata,
    price_config: PlanPriceConfig,
    credits_config: PlanCreditsConfig,
) -> Dict[str, str]:
    """
    Allows an AI Builder to create a Trial Payment Plan on Nevermined limited by duration.
    A Nevermined Trial Plan allow subscribers of that plan to test the Agents associated to it.
    A Trial plan is a plan that only can be purchased once by a user.

    Args:
        plan_metadata: Plan metadata
        price_config: Plan price configuration
        credits_config: Plan credits configuration

    Returns:
        The unique identifier of the plan (Plan ID) of the newly created plan
    """
    plan_metadata.is_trial_plan = True
    return self.register_time_plan(plan_metadata, price_config, credits_config)

get_plan

get_plan(plan_id: str) -> Dict[str, Any]

Get the metadata for a given Plan identifier.

PARAMETER DESCRIPTION
plan_id

The unique identifier of the plan

TYPE: str

RETURNS DESCRIPTION
Dict[str, Any]

The plan's metadata

RAISES DESCRIPTION
PaymentsError

If the plan is not found

Source code in payments_py/api/plans_api.py
def get_plan(self, plan_id: str) -> Dict[str, Any]:
    """
    Get the metadata for a given Plan identifier.

    Args:
        plan_id: The unique identifier of the plan

    Returns:
        The plan's metadata

    Raises:
        PaymentsError: If the plan is not found
    """
    url = f"{self.environment.backend}{API_URL_GET_PLAN.format(plan_id=plan_id)}"
    response = requests.get(url)
    if not response.ok:
        raise PaymentsError.validation(
            f"Plan not found. {response.status_code} - {response.text}"
        )
    return response.json()

get_plan_balance

get_plan_balance(
    plan_id: str, account_address: Optional[str] = None
) -> Dict[str, Any]

Get the balance of a plan for a specific account.

PARAMETER DESCRIPTION
plan_id

The unique identifier of the plan

TYPE: str

account_address

The account address to check balance for (defaults to current user)

TYPE: Optional[str] DEFAULT: None

RETURNS DESCRIPTION
Dict[str, Any]

The plan balance information with properly typed fields (balance as int)

RAISES DESCRIPTION
PaymentsError

If unable to get plan balance

Source code in payments_py/api/plans_api.py
def get_plan_balance(
    self, plan_id: str, account_address: Optional[str] = None
) -> Dict[str, Any]:
    """
    Get the balance of a plan for a specific account.

    Args:
        plan_id: The unique identifier of the plan
        account_address: The account address to check balance for (defaults to current user)

    Returns:
        The plan balance information with properly typed fields (balance as int)

    Raises:
        PaymentsError: If unable to get plan balance
    """

    if not is_ethereum_address(account_address):
        account_address = self.get_account_address()

    url = f"{self.environment.backend}{API_URL_PLAN_BALANCE.format(plan_id=plan_id, holder_address=account_address)}"
    response = requests.get(
        url,
        headers={"Accept": "application/json", "Content-Type": "application/json"},
    )
    if not response.ok:
        raise PaymentsError.internal(
            f"Unable to get plan balance. {response.status_code} - {response.text}"
        )

    # Parse and validate response using Pydantic model to ensure type conversion
    response_data = response.json()
    return PlanBalance(**response_data)

order_plan

order_plan(plan_id: str) -> Dict[str, bool]

Order a plan by its ID.

PARAMETER DESCRIPTION
plan_id

The ID of the plan to order

TYPE: str

RETURNS DESCRIPTION
Dict[str, bool]

The result of the order operation

RAISES DESCRIPTION
PaymentsError

If unable to order the plan

Source code in payments_py/api/plans_api.py
def order_plan(self, plan_id: str) -> Dict[str, bool]:
    """
    Order a plan by its ID.

    Args:
        plan_id: The ID of the plan to order

    Returns:
        The result of the order operation

    Raises:
        PaymentsError: If unable to order the plan
    """
    options = self.get_backend_http_options("POST")
    url = f"{self.environment.backend}{API_URL_ORDER_PLAN}".format(plan_id=plan_id)

    response = requests.post(url, **options)
    if not response.ok:
        raise PaymentsError.internal(
            f"Unable to order plan. {response.status_code} - {response.text}"
        )
    return response.json()

mint_plan_credits

mint_plan_credits(
    plan_id: str, credits_amount: int, credits_receiver: str
) -> Dict[str, Any]

Mint credits for a plan.

PARAMETER DESCRIPTION
plan_id

The unique identifier of the plan

TYPE: str

credits_amount

The amount of credits to mint

TYPE: int

credits_receiver

The address that will receive the credits

TYPE: str

RETURNS DESCRIPTION
Dict[str, Any]

The result of the mint operation

RAISES DESCRIPTION
PaymentsError

If unable to mint credits

Source code in payments_py/api/plans_api.py
def mint_plan_credits(
    self, plan_id: str, credits_amount: int, credits_receiver: str
) -> Dict[str, Any]:
    """
    Mint credits for a plan.

    Args:
        plan_id: The unique identifier of the plan
        credits_amount: The amount of credits to mint
        credits_receiver: The address that will receive the credits

    Returns:
        The result of the mint operation

    Raises:
        PaymentsError: If unable to mint credits
    """
    body = {
        "planId": plan_id,
        "amount": credits_amount,
        "creditsReceiver": credits_receiver,
    }
    options = self.get_backend_http_options("POST", body)
    url = f"{self.environment.backend}{API_URL_MINT_PLAN}"

    response = requests.post(url, **options)
    if not response.ok:
        raise PaymentsError.internal(
            f"Unable to mint credits. {response.status_code} - {response.text}"
        )
    return response.json()

mint_plan_expirable

mint_plan_expirable(
    plan_id: str,
    credits_amount: int,
    credits_receiver: str,
    credits_duration: int = 0,
) -> Dict[str, Any]

Mint expirable credits for a plan.

PARAMETER DESCRIPTION
plan_id

The unique identifier of the plan

TYPE: str

credits_amount

The amount of credits to mint

TYPE: int

credits_receiver

The address that will receive the credits

TYPE: str

credits_duration

The duration of the credits in seconds

TYPE: int DEFAULT: 0

RETURNS DESCRIPTION
Dict[str, Any]

The result of the mint operation

RAISES DESCRIPTION
PaymentsError

If unable to mint credits

Source code in payments_py/api/plans_api.py
def mint_plan_expirable(
    self,
    plan_id: str,
    credits_amount: int,
    credits_receiver: str,
    credits_duration: int = 0,
) -> Dict[str, Any]:
    """
    Mint expirable credits for a plan.

    Args:
        plan_id: The unique identifier of the plan
        credits_amount: The amount of credits to mint
        credits_receiver: The address that will receive the credits
        credits_duration: The duration of the credits in seconds

    Returns:
        The result of the mint operation

    Raises:
        PaymentsError: If unable to mint credits
    """
    body = {
        "planId": plan_id,
        "creditsAmount": credits_amount,
        "creditsReceiver": credits_receiver,
        "creditsDuration": credits_duration,
    }
    options = self.get_backend_http_options("POST", body)
    url = f"{self.environment.backend}{API_URL_MINT_EXPIRABLE_PLAN}"

    response = requests.post(url, **options)
    if not response.ok:
        raise PaymentsError.internal(
            f"Unable to mint expirable credits. {response.status_code} - {response.text}"
        )
    return response.json()

burn_credits

burn_credits(
    plan_id: str, credits_amount: str
) -> Dict[str, Any]

Burn credits from a plan.

PARAMETER DESCRIPTION
plan_id

The unique identifier of the plan

TYPE: str

credits_amount

The amount of credits to burn

TYPE: str

RETURNS DESCRIPTION
Dict[str, Any]

The result of the burn operation

RAISES DESCRIPTION
PaymentsError

If unable to burn credits

Source code in payments_py/api/plans_api.py
def burn_credits(self, plan_id: str, credits_amount: str) -> Dict[str, Any]:
    """
    Burn credits from a plan.

    Args:
        plan_id: The unique identifier of the plan
        credits_amount: The amount of credits to burn

    Returns:
        The result of the burn operation

    Raises:
        PaymentsError: If unable to burn credits
    """
    body = {
        "planId": plan_id,
        "creditsAmount": credits_amount,
    }
    options = self.get_backend_http_options("POST", body)
    url = f"{self.environment.backend}{API_URL_BURN_PLAN}"

    response = requests.post(url, **options)
    if not response.ok:
        raise PaymentsError.internal(
            f"Unable to burn credits. {response.status_code} - {response.text}"
        )
    return response.json()

get_agents_associated_to_plan

get_agents_associated_to_plan(
    plan_id: str,
    pagination: Optional[PaginationOptions] = None,
) -> Dict[str, Any]

Gets the list of agents that can be accessed with a plan.

PARAMETER DESCRIPTION
plan_id

The unique identifier of the plan

TYPE: str

pagination

Optional pagination options to control the number of results returned

TYPE: Optional[PaginationOptions] DEFAULT: None

RETURNS DESCRIPTION
Dict[str, Any]

The list of all different agents giving access to the plan

RAISES DESCRIPTION
PaymentsError

If the plan is not found

Source code in payments_py/api/plans_api.py
def get_agents_associated_to_plan(
    self, plan_id: str, pagination: Optional[PaginationOptions] = None
) -> Dict[str, Any]:
    """
    Gets the list of agents that can be accessed with a plan.

    Args:
        plan_id: The unique identifier of the plan
        pagination: Optional pagination options to control the number of results returned

    Returns:
        The list of all different agents giving access to the plan

    Raises:
        PaymentsError: If the plan is not found
    """
    if pagination is None:
        pagination = PaginationOptions()

    url = f"{self.environment.backend}{API_URL_GET_PLAN_AGENTS.format(plan_id=plan_id)}"
    params = {
        "page": pagination.page,
        "offset": pagination.offset,
    }
    response = requests.get(url, params=params)
    if not response.ok:
        raise PaymentsError.internal(
            f"Unable to get agents associated to plan. {response.status_code} - {response.text}"
        )
    return response.json()

get_fiat_price_config staticmethod

get_fiat_price_config(
    amount: int, receiver: str
) -> PlanPriceConfig

Build a fiat price configuration.

Source code in payments_py/api/plans_api.py
@staticmethod
def get_fiat_price_config(amount: int, receiver: str) -> PlanPriceConfig:
    """Build a fiat price configuration."""
    return plan_utils.get_fiat_price_config(amount, receiver)

get_crypto_price_config staticmethod

get_crypto_price_config(
    amount: int,
    receiver: str,
    token_address: str = "0x0000000000000000000000000000000000000000",
) -> PlanPriceConfig

Build a crypto (native/ERC20) price configuration.

Source code in payments_py/api/plans_api.py
@staticmethod
def get_crypto_price_config(
    amount: int,
    receiver: str,
    token_address: str = "0x0000000000000000000000000000000000000000",
) -> PlanPriceConfig:
    """Build a crypto (native/ERC20) price configuration."""
    return plan_utils.get_crypto_price_config(amount, receiver, token_address)

get_erc20_price_config staticmethod

get_erc20_price_config(
    amount: int, token_address: str, receiver: str
) -> PlanPriceConfig

Build an ERC20 price configuration.

Source code in payments_py/api/plans_api.py
@staticmethod
def get_erc20_price_config(
    amount: int, token_address: str, receiver: str
) -> PlanPriceConfig:
    """Build an ERC20 price configuration."""
    return plan_utils.get_erc20_price_config(amount, token_address, receiver)

get_free_price_config staticmethod

get_free_price_config() -> PlanPriceConfig

Build a free price configuration.

Source code in payments_py/api/plans_api.py
@staticmethod
def get_free_price_config() -> PlanPriceConfig:
    """Build a free price configuration."""
    return plan_utils.get_free_price_config()

get_native_token_price_config staticmethod

get_native_token_price_config(
    amount: int, receiver: str
) -> PlanPriceConfig

Build a native token price configuration.

Source code in payments_py/api/plans_api.py
@staticmethod
def get_native_token_price_config(amount: int, receiver: str) -> PlanPriceConfig:
    """Build a native token price configuration."""
    return plan_utils.get_native_token_price_config(amount, receiver)

get_expirable_duration_config staticmethod

get_expirable_duration_config(
    duration_of_plan: int,
) -> PlanCreditsConfig

Build an expirable duration credits configuration.

Source code in payments_py/api/plans_api.py
@staticmethod
def get_expirable_duration_config(duration_of_plan: int) -> PlanCreditsConfig:
    """Build an expirable duration credits configuration."""
    return plan_utils.get_expirable_duration_config(duration_of_plan)

get_non_expirable_duration_config staticmethod

get_non_expirable_duration_config() -> PlanCreditsConfig

Build a non-expirable duration credits configuration.

Source code in payments_py/api/plans_api.py
@staticmethod
def get_non_expirable_duration_config() -> PlanCreditsConfig:
    """Build a non-expirable duration credits configuration."""
    return plan_utils.get_non_expirable_duration_config()

get_fixed_credits_config staticmethod

get_fixed_credits_config(
    credits_granted: int, credits_per_request: int = 1
) -> PlanCreditsConfig

Build a fixed credits configuration.

Source code in payments_py/api/plans_api.py
@staticmethod
def get_fixed_credits_config(
    credits_granted: int, credits_per_request: int = 1
) -> PlanCreditsConfig:
    """Build a fixed credits configuration."""
    return plan_utils.get_fixed_credits_config(credits_granted, credits_per_request)

get_dynamic_credits_config staticmethod

get_dynamic_credits_config(
    credits_granted: int,
    min_credits_per_request: int = 1,
    max_credits_per_request: int = 1,
) -> PlanCreditsConfig

Build a dynamic credits configuration.

Source code in payments_py/api/plans_api.py
@staticmethod
def get_dynamic_credits_config(
    credits_granted: int,
    min_credits_per_request: int = 1,
    max_credits_per_request: int = 1,
) -> PlanCreditsConfig:
    """Build a dynamic credits configuration."""
    return plan_utils.get_dynamic_credits_config(
        credits_granted, min_credits_per_request, max_credits_per_request
    )

set_redemption_type staticmethod

set_redemption_type(
    credits_config: PlanCreditsConfig,
    redemption_type: PlanRedemptionType,
) -> PlanCreditsConfig

Set redemption type on a credits configuration (returns new object).

Source code in payments_py/api/plans_api.py
@staticmethod
def set_redemption_type(
    credits_config: PlanCreditsConfig, redemption_type: PlanRedemptionType
) -> PlanCreditsConfig:
    """Set redemption type on a credits configuration (returns new object)."""
    return plan_utils.set_redemption_type(credits_config, redemption_type)

set_proof_required staticmethod

set_proof_required(
    credits_config: PlanCreditsConfig,
    proof_required: bool = True,
) -> PlanCreditsConfig

Set proof requirement on a credits configuration (returns new object).

Source code in payments_py/api/plans_api.py
@staticmethod
def set_proof_required(
    credits_config: PlanCreditsConfig, proof_required: bool = True
) -> PlanCreditsConfig:
    """Set proof requirement on a credits configuration (returns new object)."""
    return plan_utils.set_proof_required(credits_config, proof_required)

get_pay_as_you_go_price_config

get_pay_as_you_go_price_config(
    amount: int,
    receiver: str,
    token_address: str = plan_utils.ZeroAddress,
) -> PlanPriceConfig

Build a pay-as-you-go price configuration using contract address from API.

This method fetches the PayAsYouGoTemplate contract address from the API info endpoint and uses it to create the price configuration. The address is cached for subsequent calls.

PARAMETER DESCRIPTION
amount

The amount per usage in the smallest unit of the token

TYPE: int

receiver

The address that will receive the payment

TYPE: str

token_address

The address of the token to use for payment (defaults to native token)

TYPE: str DEFAULT: ZeroAddress

RETURNS DESCRIPTION
PlanPriceConfig

A PlanPriceConfig object configured for pay-as-you-go payments

RAISES DESCRIPTION
PaymentsError

If unable to fetch contract address from API

ValueError

If the receiver address is not a valid Ethereum address

Source code in payments_py/api/plans_api.py
def get_pay_as_you_go_price_config(
    self,
    amount: int,
    receiver: str,
    token_address: str = plan_utils.ZeroAddress,
) -> PlanPriceConfig:
    """
    Build a pay-as-you-go price configuration using contract address from API.

    This method fetches the PayAsYouGoTemplate contract address from the API info endpoint
    and uses it to create the price configuration. The address is cached for subsequent calls.

    Args:
        amount: The amount per usage in the smallest unit of the token
        receiver: The address that will receive the payment
        token_address: The address of the token to use for payment (defaults to native token)

    Returns:
        A PlanPriceConfig object configured for pay-as-you-go payments

    Raises:
        PaymentsError: If unable to fetch contract address from API
        ValueError: If the receiver address is not a valid Ethereum address
    """
    # Get contract address from contracts API
    template_address = self.contracts_api.contracts.pay_as_you_go_template

    return get_pay_as_you_go_price_config(
        amount, receiver, token_address, template_address=template_address
    )

get_pay_as_you_go_credits_config staticmethod

get_pay_as_you_go_credits_config() -> PlanCreditsConfig

Build a pay-as-you-go credits configuration.

Source code in payments_py/api/plans_api.py
@staticmethod
def get_pay_as_you_go_credits_config() -> PlanCreditsConfig:
    """Build a pay-as-you-go credits configuration."""
    return get_pay_as_you_go_credits_config()

order_fiat_plan

order_fiat_plan(plan_id: str) -> Dict[str, Any]

Order a fiat plan using Stripe checkout.

PARAMETER DESCRIPTION
plan_id

The unique identifier of the plan

TYPE: str

RETURNS DESCRIPTION
Dict[str, Any]

The Stripe checkout result

RAISES DESCRIPTION
PaymentsError

If unable to order the fiat plan

Source code in payments_py/api/plans_api.py
def order_fiat_plan(self, plan_id: str) -> Dict[str, Any]:
    """
    Order a fiat plan using Stripe checkout.

    Args:
        plan_id: The unique identifier of the plan

    Returns:
        The Stripe checkout result

    Raises:
        PaymentsError: If unable to order the fiat plan
    """
    body = {"planId": plan_id, "sessionType": "embedded"}
    options = self.get_backend_http_options("POST", body)
    url = f"{self.environment.backend}{API_URL_STRIPE_CHECKOUT}"

    response = requests.post(url, **options)
    if not response.ok:
        raise PaymentsError.internal(
            f"Unable to order fiat plan. {response.status_code} - {response.text}"
        )
    return response.json()

redeem_credits

redeem_credits(
    agent_request_id: str,
    plan_id: str,
    redeem_from: str,
    credits_amount_to_redeem: str,
) -> Dict[str, Any]

Redeem credits from a plan for a specific agent request.

PARAMETER DESCRIPTION
agent_request_id

The unique identifier of the agent request

TYPE: str

plan_id

The unique identifier of the plan

TYPE: str

redeem_from

The address to redeem credits from

TYPE: str

credits_amount_to_redeem

The amount of credits to redeem

TYPE: str

RETURNS DESCRIPTION
Dict[str, Any]

The result of the redeem operation

RAISES DESCRIPTION
PaymentsError

If unable to redeem credits

Source code in payments_py/api/plans_api.py
def redeem_credits(
    self,
    agent_request_id: str,
    plan_id: str,
    redeem_from: str,
    credits_amount_to_redeem: str,
) -> Dict[str, Any]:
    """
    Redeem credits from a plan for a specific agent request.

    Args:
        agent_request_id: The unique identifier of the agent request
        plan_id: The unique identifier of the plan
        redeem_from: The address to redeem credits from
        credits_amount_to_redeem: The amount of credits to redeem

    Returns:
        The result of the redeem operation

    Raises:
        PaymentsError: If unable to redeem credits
    """
    body = {
        "agentRequestId": agent_request_id,
        "planId": plan_id,
        "redeemFrom": redeem_from,
        "amount": credits_amount_to_redeem,
    }
    options = self.get_backend_http_options("POST", body)
    url = f"{self.environment.backend}{API_URL_REDEEM_PLAN}"

    response = requests.post(url, **options)
    if not response.ok:
        raise PaymentsError.internal(
            f"Unable to redeem credits. {response.status_code} - {response.text}"
        )
    return response.json()

Agents API

AgentsAPI

AgentsAPI(options: PaymentOptions)

Bases: BasePaymentsAPI

The AgentsAPI class provides methods to register and interact with AI Agents on Nevermined.

Source code in payments_py/api/base_payments.py
def __init__(self, options: PaymentOptions):
    """
    Initialize the base payments API.

    Args:
        options: The options to initialize the payments class
    """
    self.nvm_api_key = options.nvm_api_key
    self.return_url = options.return_url or ""
    self.environment = get_environment(options.environment)
    self.environment_name = options.environment
    self.app_id = options.app_id
    self.version = options.version
    self.account_address: Optional[str] = None
    self.helicone_api_key: str = None
    self.is_browser_instance = True
    self._parse_nvm_api_key()

get_instance classmethod

get_instance(options: PaymentOptions) -> AgentsAPI

Get a singleton instance of the AgentsAPI class.

PARAMETER DESCRIPTION
options

The options to initialize the payments class

TYPE: PaymentOptions

RETURNS DESCRIPTION
AgentsAPI

The instance of the AgentsAPI class

Source code in payments_py/api/agents_api.py
@classmethod
def get_instance(cls, options: PaymentOptions) -> "AgentsAPI":
    """
    Get a singleton instance of the AgentsAPI class.

    Args:
        options: The options to initialize the payments class

    Returns:
        The instance of the AgentsAPI class
    """
    return cls(options)

register_agent

register_agent(
    agent_metadata: AgentMetadata,
    agent_api: AgentAPIAttributes,
    payment_plans: List[str],
) -> Dict[str, str]

Registers a new AI Agent on Nevermined. The agent must be associated to one or multiple Payment Plans. Users that are subscribers of a payment plan can query the agent. Depending on the Payment Plan and the configuration of the agent, the usage of the agent/service will consume credits. When the plan expires (because the time is over or the credits are consumed), the user needs to renew the plan to continue using the agent.

PARAMETER DESCRIPTION
agent_metadata

Agent metadata

TYPE: AgentMetadata

agent_api

Agent API attributes

TYPE: AgentAPIAttributes

payment_plans

The list of payment plans giving access to the agent

TYPE: List[str]

RETURNS DESCRIPTION
Dict[str, str]

The unique identifier of the newly created agent (Agent Id)

RAISES DESCRIPTION
PaymentsError

If registration fails

Source code in payments_py/api/agents_api.py
def register_agent(
    self,
    agent_metadata: AgentMetadata,
    agent_api: AgentAPIAttributes,
    payment_plans: List[str],
) -> Dict[str, str]:
    """
    Registers a new AI Agent on Nevermined.
    The agent must be associated to one or multiple Payment Plans. Users that are subscribers of a payment plan can query the agent.
    Depending on the Payment Plan and the configuration of the agent, the usage of the agent/service will consume credits.
    When the plan expires (because the time is over or the credits are consumed), the user needs to renew the plan to continue using the agent.

    Args:
        agent_metadata: Agent metadata
        agent_api: Agent API attributes
        payment_plans: The list of payment plans giving access to the agent

    Returns:
        The unique identifier of the newly created agent (Agent Id)

    Raises:
        PaymentsError: If registration fails
    """
    body = {
        "metadataAttributes": self.pydantic_to_dict(agent_metadata),
        "agentApiAttributes": self.pydantic_to_dict(agent_api),
        "plans": payment_plans,
    }

    options = self.get_backend_http_options("POST", body)
    url = f"{self.environment.backend}{API_URL_REGISTER_AGENT}"

    response = requests.post(url, **options)
    if not response.ok:
        try:
            error = response.json()
        except Exception:
            error = {"message": response.text, "code": response.status_code}
        raise PaymentsError.from_backend("Unable to register agent", error)
    agent_data = response.json()
    return {"agentId": agent_data["data"]["agentId"]}

register_agent_and_plan

register_agent_and_plan(
    agent_metadata: AgentMetadata,
    agent_api: AgentAPIAttributes,
    plan_metadata: PlanMetadata,
    price_config: PlanPriceConfig,
    credits_config: PlanCreditsConfig,
    access_limit: Optional[
        Literal["credits", "time"]
    ] = None,
) -> Dict[str, str]

Registers a new AI Agent and a Payment Plan associated to this new agent. Depending on the Payment Plan and the configuration of the agent, the usage of the agent/service will consume credits. When the plan expires (because the time is over or the credits are consumed), the user needs to renew the plan to continue using the agent.

PARAMETER DESCRIPTION
agent_metadata

Agent metadata

TYPE: AgentMetadata

agent_api

Agent API attributes

TYPE: AgentAPIAttributes

plan_metadata

Plan metadata

TYPE: PlanMetadata

price_config

Plan price configuration

TYPE: PlanPriceConfig

credits_config

Plan credits configuration

TYPE: PlanCreditsConfig

access_limit

Optional access limit for the plan

TYPE: Optional[Literal['credits', 'time']] DEFAULT: None

Returns: Dictionary containing agentId, planId, and txHash

RAISES DESCRIPTION
PaymentsError

If registration fails

Source code in payments_py/api/agents_api.py
def register_agent_and_plan(
    self,
    agent_metadata: AgentMetadata,
    agent_api: AgentAPIAttributes,
    plan_metadata: PlanMetadata,
    price_config: PlanPriceConfig,
    credits_config: PlanCreditsConfig,
    access_limit: Optional[Literal["credits", "time"]] = None,
) -> Dict[str, str]:
    """
    Registers a new AI Agent and a Payment Plan associated to this new agent.
    Depending on the Payment Plan and the configuration of the agent, the usage of the agent/service will consume credits.
    When the plan expires (because the time is over or the credits are consumed), the user needs to renew the plan to continue using the agent.

    Args:
        agent_metadata: Agent metadata
        agent_api: Agent API attributes
        plan_metadata: Plan metadata
        price_config: Plan price configuration
        credits_config: Plan credits configuration
        access_limit: Optional access limit for the plan
    Returns:
        Dictionary containing agentId, planId, and txHash

    Raises:
        PaymentsError: If registration fails
    """
    if access_limit and access_limit not in ["credits", "time"]:
        raise PaymentsError.validation(
            "Invalid access limit",
            "accessLimit must be either 'credits' or 'time'",
        )
    if not access_limit:
        access_limit = "time" if credits_config.duration_secs > 0 else "credits"

    body = {
        "plan": {
            "metadataAttributes": self.pydantic_to_dict(plan_metadata),
            "priceConfig": self.pydantic_to_dict(price_config),
            "creditsConfig": self.pydantic_to_dict(credits_config),
            "accessLimit": access_limit,
        },
        "agent": {
            "metadataAttributes": self.pydantic_to_dict(agent_metadata),
            "agentApiAttributes": self.pydantic_to_dict(agent_api),
        },
    }

    options = self.get_backend_http_options("POST", body)
    url = f"{self.environment.backend}{API_URL_REGISTER_AGENTS_AND_PLAN}"

    response = requests.post(url, **options)
    if not response.ok:
        try:
            error = response.json()
        except Exception:
            error = {"message": response.text, "code": response.status_code}
        raise PaymentsError.from_backend("Unable to register agent & plan", error)
    result = response.json()

    return {
        "agentId": result["data"]["agentId"],
        "planId": result["data"]["planId"],
        "txHash": result["txHash"],
    }

get_agent

get_agent(agent_id: str) -> Dict[str, Any]

Gets the metadata for a given Agent identifier.

PARAMETER DESCRIPTION
agent_id

The unique identifier of the agent

TYPE: str

RETURNS DESCRIPTION
Dict[str, Any]

The agent's metadata

RAISES DESCRIPTION
PaymentsError

If the agent is not found

Source code in payments_py/api/agents_api.py
def get_agent(self, agent_id: str) -> Dict[str, Any]:
    """
    Gets the metadata for a given Agent identifier.

    Args:
        agent_id: The unique identifier of the agent

    Returns:
        The agent's metadata

    Raises:
        PaymentsError: If the agent is not found
    """
    url = f"{self.environment.backend}{API_URL_GET_AGENT.format(agent_id=agent_id)}"
    response = requests.get(url)
    if not response.ok:
        try:
            error = response.json()
        except Exception:
            error = {"message": response.text, "code": response.status_code}
        raise PaymentsError.from_backend("Agent not found", error)
    return response.json()

get_agent_plans

get_agent_plans(
    agent_id: str,
    pagination: Optional[PaginationOptions] = None,
) -> Dict[str, Any]

Gets the list of plans that can be ordered to get access to an agent.

PARAMETER DESCRIPTION
agent_id

The unique identifier of the agent

TYPE: str

pagination

Optional pagination options to control the number of results returned

TYPE: Optional[PaginationOptions] DEFAULT: None

RETURNS DESCRIPTION
Dict[str, Any]

The list of all different plans giving access to the agent

RAISES DESCRIPTION
PaymentsError

If the agent is not found

Source code in payments_py/api/agents_api.py
def get_agent_plans(
    self, agent_id: str, pagination: Optional[PaginationOptions] = None
) -> Dict[str, Any]:
    """
    Gets the list of plans that can be ordered to get access to an agent.

    Args:
        agent_id: The unique identifier of the agent
        pagination: Optional pagination options to control the number of results returned

    Returns:
        The list of all different plans giving access to the agent

    Raises:
        PaymentsError: If the agent is not found
    """
    if pagination is None:
        pagination = PaginationOptions()

    url = f"{self.environment.backend}{API_URL_GET_AGENT_PLANS.format(agent_id=agent_id)}"
    params = {
        "page": pagination.page,
        "offset": pagination.offset,
    }
    response = requests.get(url, params=params)
    if not response.ok:
        try:
            error = response.json()
        except Exception:
            error = {"message": response.text, "code": response.status_code}
        raise PaymentsError.from_backend("Unable to get agent plans", error)
    return response.json()

add_plan_to_agent

add_plan_to_agent(
    plan_id: str, agent_id: str
) -> Dict[str, Any]

Add a plan to an agent.

PARAMETER DESCRIPTION
plan_id

The unique identifier of the plan

TYPE: str

agent_id

The unique identifier of the agent

TYPE: str

RETURNS DESCRIPTION
Dict[str, Any]

The result of the operation

RAISES DESCRIPTION
PaymentsError

If unable to add plan to agent

Source code in payments_py/api/agents_api.py
def add_plan_to_agent(self, plan_id: str, agent_id: str) -> Dict[str, Any]:
    """
    Add a plan to an agent.

    Args:
        plan_id: The unique identifier of the plan
        agent_id: The unique identifier of the agent

    Returns:
        The result of the operation

    Raises:
        PaymentsError: If unable to add plan to agent
    """
    options = self.get_backend_http_options("POST")
    url = f"{self.environment.backend}{API_URL_ADD_PLAN_AGENT.format(agent_id=agent_id, plan_id=plan_id)}"

    response = requests.post(url, **options)
    if not response.ok:
        try:
            error = response.json()
        except Exception:
            error = {"message": response.text, "code": response.status_code}
        raise PaymentsError.from_backend("Unable to add plan to agent", error)
    return response.json()

remove_plan_from_agent

remove_plan_from_agent(
    plan_id: str, agent_id: str
) -> Dict[str, Any]

Remove a plan from an agent.

PARAMETER DESCRIPTION
plan_id

The unique identifier of the plan

TYPE: str

agent_id

The unique identifier of the agent

TYPE: str

RETURNS DESCRIPTION
Dict[str, Any]

The result of the operation

RAISES DESCRIPTION
PaymentsError

If unable to remove plan from agent

Source code in payments_py/api/agents_api.py
def remove_plan_from_agent(self, plan_id: str, agent_id: str) -> Dict[str, Any]:
    """
    Remove a plan from an agent.

    Args:
        plan_id: The unique identifier of the plan
        agent_id: The unique identifier of the agent

    Returns:
        The result of the operation

    Raises:
        PaymentsError: If unable to remove plan from agent
    """
    url = f"{self.environment.backend}{API_URL_REMOVE_PLAN_AGENT.format(agent_id=agent_id, plan_id=plan_id)}"
    options = self.get_backend_http_options("DELETE")

    response = requests.delete(url, **options)
    if not response.ok:
        try:
            error = response.json()
        except Exception:
            error = {"message": response.text, "code": response.status_code}
        raise PaymentsError.from_backend("Unable to remove plan from agent", error)
    return response.json()

update_agent_metadata

update_agent_metadata(
    agent_id: str,
    agent_metadata: AgentMetadata,
    agent_api: AgentAPIAttributes,
) -> Dict[str, Any]

Updates the metadata and API attributes of an existing AI Agent.

PARAMETER DESCRIPTION
agent_id

The unique identifier of the agent

TYPE: str

agent_metadata

The new metadata attributes for the agent

TYPE: AgentMetadata

agent_api

The new API attributes for the agent

TYPE: AgentAPIAttributes

RETURNS DESCRIPTION
Dict[str, Any]

The result of the update operation

RAISES DESCRIPTION
PaymentsError

If the agent is not found or if the update fails

Source code in payments_py/api/agents_api.py
def update_agent_metadata(
    self,
    agent_id: str,
    agent_metadata: AgentMetadata,
    agent_api: AgentAPIAttributes,
) -> Dict[str, Any]:
    """
    Updates the metadata and API attributes of an existing AI Agent.

    Args:
        agent_id: The unique identifier of the agent
        agent_metadata: The new metadata attributes for the agent
        agent_api: The new API attributes for the agent

    Returns:
        The result of the update operation

    Raises:
        PaymentsError: If the agent is not found or if the update fails
    """
    body = {
        "metadataAttributes": self.pydantic_to_dict(agent_metadata),
        "agentApiAttributes": self.pydantic_to_dict(agent_api),
    }
    url = f"{self.environment.backend}{API_URL_UPDATE_AGENT.format(agent_id=agent_id)}"
    options = self.get_backend_http_options("PUT", body)
    response = requests.put(url, **options)
    if not response.ok:
        try:
            error = response.json()
        except Exception:
            error = {"message": response.text, "code": response.status_code}
        raise PaymentsError.from_backend("Error updating agent", error)
    return response.json()

Facilitator API (x402)

FacilitatorAPI

FacilitatorAPI(options: PaymentOptions)

Bases: BasePaymentsAPI

The FacilitatorAPI class provides methods to verify and settle AI agent permissions. It enables AI agents to act as facilitators, managing credit verification and settlement for subscribers using X402 access tokens.

Source code in payments_py/api/base_payments.py
def __init__(self, options: PaymentOptions):
    """
    Initialize the base payments API.

    Args:
        options: The options to initialize the payments class
    """
    self.nvm_api_key = options.nvm_api_key
    self.return_url = options.return_url or ""
    self.environment = get_environment(options.environment)
    self.environment_name = options.environment
    self.app_id = options.app_id
    self.version = options.version
    self.account_address: Optional[str] = None
    self.helicone_api_key: str = None
    self.is_browser_instance = True
    self._parse_nvm_api_key()

get_instance classmethod

get_instance(options: PaymentOptions) -> FacilitatorAPI

Get a singleton instance of the FacilitatorAPI class.

PARAMETER DESCRIPTION
options

The options to initialize the payments class

TYPE: PaymentOptions

RETURNS DESCRIPTION
FacilitatorAPI

The instance of the FacilitatorAPI class

Source code in payments_py/x402/facilitator_api.py
@classmethod
def get_instance(cls, options: PaymentOptions) -> "FacilitatorAPI":
    """
    Get a singleton instance of the FacilitatorAPI class.

    Args:
        options: The options to initialize the payments class

    Returns:
        The instance of the FacilitatorAPI class
    """
    return cls(options)

verify_permissions

verify_permissions(
    payment_required: X402PaymentRequired,
    x402_access_token: str,
    max_amount: Optional[str] = None,
) -> VerifyResponse

Verify if a subscriber has permission to use credits from a payment plan. This method simulates the credit usage without actually burning credits, checking if the subscriber has sufficient balance and permissions.

The planId and subscriberAddress are extracted from the x402AccessToken.

PARAMETER DESCRIPTION
payment_required

x402 PaymentRequired from 402 response (required, for validation)

TYPE: X402PaymentRequired

x402_access_token

The X402 access token (contains planId, subscriberAddress, agentId)

TYPE: str

max_amount

The maximum number of credits to verify (as string, optional)

TYPE: Optional[str] DEFAULT: None

RETURNS DESCRIPTION
VerifyResponse

VerifyResponse with is_valid boolean and optional error details

RAISES DESCRIPTION
PaymentsError

If verification fails

Source code in payments_py/x402/facilitator_api.py
def verify_permissions(
    self,
    payment_required: X402PaymentRequired,
    x402_access_token: str,
    max_amount: Optional[str] = None,
) -> VerifyResponse:
    """
    Verify if a subscriber has permission to use credits from a payment plan.
    This method simulates the credit usage without actually burning credits,
    checking if the subscriber has sufficient balance and permissions.

    The planId and subscriberAddress are extracted from the x402AccessToken.

    Args:
        payment_required: x402 PaymentRequired from 402 response (required, for validation)
        x402_access_token: The X402 access token (contains planId, subscriberAddress, agentId)
        max_amount: The maximum number of credits to verify (as string, optional)

    Returns:
        VerifyResponse with is_valid boolean and optional error details

    Raises:
        PaymentsError: If verification fails
    """
    url = f"{self.environment.backend}{API_URL_VERIFY_PERMISSIONS}"

    body: dict = {
        "paymentRequired": payment_required.model_dump(by_alias=True),
        "x402AccessToken": x402_access_token,
    }

    if max_amount is not None:
        body["maxAmount"] = max_amount

    options = self.get_public_http_options("POST", body)

    try:
        response = requests.post(url, **options)
        response.raise_for_status()
        return VerifyResponse.model_validate(response.json())
    except requests.HTTPError as err:
        try:
            error_message = response.json().get(
                "message", "Permission verification failed"
            )
        except Exception:
            error_message = "Permission verification failed"
        raise PaymentsError.from_backend(
            error_message,
            {"code": f"HTTP {response.status_code}"},
        ) from err
    except Exception as err:
        if isinstance(err, PaymentsError):
            raise
        raise PaymentsError.from_backend(
            "Network error during permission verification",
            {"code": "network_error", "message": str(err)},
        ) from err

settle_permissions

settle_permissions(
    payment_required: X402PaymentRequired,
    x402_access_token: str,
    max_amount: Optional[str] = None,
    agent_request_id: Optional[str] = None,
) -> SettleResponse

Settle (burn) credits from a subscriber's payment plan. This method executes the actual credit consumption, burning the specified number of credits from the subscriber's balance. If the subscriber doesn't have enough credits, it will attempt to order more before settling.

The planId and subscriberAddress are extracted from the x402AccessToken.

PARAMETER DESCRIPTION
payment_required

x402 PaymentRequired from 402 response (required, for validation)

TYPE: X402PaymentRequired

x402_access_token

The X402 access token (contains planId, subscriberAddress, agentId)

TYPE: str

max_amount

The number of credits to burn (as string, optional)

TYPE: Optional[str] DEFAULT: None

agent_request_id

Agent request ID for observability tracking (optional)

TYPE: Optional[str] DEFAULT: None

RETURNS DESCRIPTION
SettleResponse

SettleResponse with success boolean and transaction details

RAISES DESCRIPTION
PaymentsError

If settlement fails

Source code in payments_py/x402/facilitator_api.py
def settle_permissions(
    self,
    payment_required: X402PaymentRequired,
    x402_access_token: str,
    max_amount: Optional[str] = None,
    agent_request_id: Optional[str] = None,
) -> SettleResponse:
    """
    Settle (burn) credits from a subscriber's payment plan.
    This method executes the actual credit consumption, burning the specified
    number of credits from the subscriber's balance. If the subscriber doesn't
    have enough credits, it will attempt to order more before settling.

    The planId and subscriberAddress are extracted from the x402AccessToken.

    Args:
        payment_required: x402 PaymentRequired from 402 response (required, for validation)
        x402_access_token: The X402 access token (contains planId, subscriberAddress, agentId)
        max_amount: The number of credits to burn (as string, optional)
        agent_request_id: Agent request ID for observability tracking (optional)

    Returns:
        SettleResponse with success boolean and transaction details

    Raises:
        PaymentsError: If settlement fails
    """
    url = f"{self.environment.backend}{API_URL_SETTLE_PERMISSIONS}"

    body: dict = {
        "paymentRequired": payment_required.model_dump(by_alias=True),
        "x402AccessToken": x402_access_token,
    }

    if max_amount is not None:
        body["maxAmount"] = max_amount

    if agent_request_id is not None:
        body["agentRequestId"] = agent_request_id

    options = self.get_public_http_options("POST", body)

    try:
        response = requests.post(url, **options)
        response.raise_for_status()
        return SettleResponse.model_validate(response.json())
    except requests.HTTPError as err:
        try:
            error_message = response.json().get(
                "message", "Permission settlement failed"
            )
        except Exception:
            error_message = "Permission settlement failed"
        raise PaymentsError.from_backend(
            error_message,
            {"code": f"HTTP {response.status_code}"},
        ) from err
    except Exception as err:
        if isinstance(err, PaymentsError):
            raise
        raise PaymentsError.from_backend(
            "Network error during permission settlement",
            {"code": "network_error", "message": str(err)},
        ) from err

X402 Token API

X402TokenAPI

X402TokenAPI(options: PaymentOptions)

Bases: BasePaymentsAPI

X402 Token API for generating access tokens.

Handles X402 access token generation for subscribers to authorize payment operations with AI agents.

Source code in payments_py/api/base_payments.py
def __init__(self, options: PaymentOptions):
    """
    Initialize the base payments API.

    Args:
        options: The options to initialize the payments class
    """
    self.nvm_api_key = options.nvm_api_key
    self.return_url = options.return_url or ""
    self.environment = get_environment(options.environment)
    self.environment_name = options.environment
    self.app_id = options.app_id
    self.version = options.version
    self.account_address: Optional[str] = None
    self.helicone_api_key: str = None
    self.is_browser_instance = True
    self._parse_nvm_api_key()

get_instance classmethod

get_instance(options: PaymentOptions) -> X402TokenAPI

Get a singleton instance of the X402TokenAPI class.

PARAMETER DESCRIPTION
options

The options to initialize the API

TYPE: PaymentOptions

RETURNS DESCRIPTION
X402TokenAPI

The instance of the X402TokenAPI class

Source code in payments_py/x402/token.py
@classmethod
def get_instance(cls, options: PaymentOptions) -> "X402TokenAPI":
    """
    Get a singleton instance of the X402TokenAPI class.

    Args:
        options: The options to initialize the API

    Returns:
        The instance of the X402TokenAPI class
    """
    return cls(options)

get_x402_access_token

get_x402_access_token(
    plan_id: str,
    agent_id: Optional[str] = None,
    redemption_limit: Optional[int] = None,
    order_limit: Optional[str] = None,
    expiration: Optional[str] = None,
) -> Dict[str, Any]

Create a permission and get an X402 access token for the given plan.

This token allows the agent to verify and settle permissions on behalf of the subscriber. The token contains cryptographically signed session keys that delegate specific permissions (order, burn) to the agent.

PARAMETER DESCRIPTION
plan_id

The unique identifier of the payment plan

TYPE: str

agent_id

The unique identifier of the AI agent (optional)

TYPE: Optional[str] DEFAULT: None

redemption_limit

Maximum number of interactions/redemptions allowed (optional)

TYPE: Optional[int] DEFAULT: None

order_limit

Maximum spend limit in token units (wei) for ordering (optional)

TYPE: Optional[str] DEFAULT: None

expiration

Expiration date in ISO 8601 format, e.g. "2025-02-01T10:00:00Z" (optional)

TYPE: Optional[str] DEFAULT: None

RETURNS DESCRIPTION
Dict[str, Any]

A dictionary containing: - accessToken: The X402 access token string

RAISES DESCRIPTION
PaymentsError

If the request fails

Example
from payments_py import Payments, PaymentOptions
from payments_py.x402 import X402TokenAPI

payments = Payments.get_instance(
    PaymentOptions(nvm_api_key="nvm:subscriber-key", environment="sandbox")
)

token_api = X402TokenAPI.get_instance(payments.options)
result = token_api.get_x402_access_token(plan_id="123", agent_id="456")
token = result["accessToken"]
Source code in payments_py/x402/token.py
def get_x402_access_token(
    self,
    plan_id: str,
    agent_id: Optional[str] = None,
    redemption_limit: Optional[int] = None,
    order_limit: Optional[str] = None,
    expiration: Optional[str] = None,
) -> Dict[str, Any]:
    """
    Create a permission and get an X402 access token for the given plan.

    This token allows the agent to verify and settle permissions on behalf
    of the subscriber. The token contains cryptographically signed session keys
    that delegate specific permissions (order, burn) to the agent.

    Args:
        plan_id: The unique identifier of the payment plan
        agent_id: The unique identifier of the AI agent (optional)
        redemption_limit: Maximum number of interactions/redemptions allowed (optional)
        order_limit: Maximum spend limit in token units (wei) for ordering (optional)
        expiration: Expiration date in ISO 8601 format, e.g. "2025-02-01T10:00:00Z" (optional)

    Returns:
        A dictionary containing:
            - accessToken: The X402 access token string

    Raises:
        PaymentsError: If the request fails

    Example:
        ```python
        from payments_py import Payments, PaymentOptions
        from payments_py.x402 import X402TokenAPI

        payments = Payments.get_instance(
            PaymentOptions(nvm_api_key="nvm:subscriber-key", environment="sandbox")
        )

        token_api = X402TokenAPI.get_instance(payments.options)
        result = token_api.get_x402_access_token(plan_id="123", agent_id="456")
        token = result["accessToken"]
        ```
    """
    url = f"{self.environment.backend}{API_URL_CREATE_PERMISSION}"

    # Build x402-aligned request body
    extra: Dict[str, Any] = {}
    if agent_id is not None:
        extra["agentId"] = agent_id

    body: Dict[str, Any] = {
        "accepted": {
            "scheme": "nvm:erc4337",
            "network": "eip155:84532",
            "planId": plan_id,
            "extra": extra,
        },
    }

    # Add session key config if any options are provided
    session_key_config: Dict[str, Any] = {}
    if redemption_limit is not None:
        session_key_config["redemptionLimit"] = redemption_limit
    if order_limit is not None:
        session_key_config["orderLimit"] = order_limit
    if expiration is not None:
        session_key_config["expiration"] = expiration
    if session_key_config:
        body["sessionKeyConfig"] = session_key_config

    options = self.get_backend_http_options("POST", body)

    try:
        response = requests.post(url, **options)
        response.raise_for_status()
        return response.json()
    except requests.HTTPError as err:
        try:
            error_message = response.json().get(
                "message", "Failed to create X402 permission"
            )
        except Exception:
            error_message = "Failed to create X402 permission"
        raise PaymentsError.internal(
            f"{error_message} (HTTP {response.status_code})"
        ) from err
    except Exception as err:
        raise PaymentsError.internal(
            f"Network error while creating X402 permission: {str(err)}"
        ) from err

Requests API

AgentRequestsAPI

AgentRequestsAPI(options: PaymentOptions)

Bases: BasePaymentsAPI

The AgentRequestsAPI class provides methods to manage the requests received by AI Agents integrated with Nevermined.

Note: For request validation and credit settlement, use the x402 API instead: - payments.facilitator.verify_permissions() - to verify token and permissions - payments.facilitator.settle_permissions() - to burn credits

Source code in payments_py/api/base_payments.py
def __init__(self, options: PaymentOptions):
    """
    Initialize the base payments API.

    Args:
        options: The options to initialize the payments class
    """
    self.nvm_api_key = options.nvm_api_key
    self.return_url = options.return_url or ""
    self.environment = get_environment(options.environment)
    self.environment_name = options.environment
    self.app_id = options.app_id
    self.version = options.version
    self.account_address: Optional[str] = None
    self.helicone_api_key: str = None
    self.is_browser_instance = True
    self._parse_nvm_api_key()

get_instance classmethod

get_instance(options: PaymentOptions) -> AgentRequestsAPI

Get a singleton instance of the AgentRequestsAPI class.

PARAMETER DESCRIPTION
options

The options to initialize the payments class

TYPE: PaymentOptions

RETURNS DESCRIPTION
AgentRequestsAPI

The instance of the AgentRequestsAPI class

Source code in payments_py/api/requests_api.py
@classmethod
def get_instance(cls, options: PaymentOptions) -> "AgentRequestsAPI":
    """
    Get a singleton instance of the AgentRequestsAPI class.

    Args:
        options: The options to initialize the payments class

    Returns:
        The instance of the AgentRequestsAPI class
    """
    return cls(options)

track_agent_sub_task

track_agent_sub_task(
    track_agent_sub_task: TrackAgentSubTaskDto,
) -> Dict[str, Any]

Tracks an agent sub task.

This method is used by agent owners to track agent sub tasks for agent tasks. It records information about credit redemption, categorization tags, and processing descriptions.

PARAMETER DESCRIPTION
track_agent_sub_task

The agent sub task data to track

TYPE: TrackAgentSubTaskDto

RETURNS DESCRIPTION
Dict[str, Any]

A promise that resolves to the result of the operation

RAISES DESCRIPTION
PaymentsError

If unable to track the agent sub task

Source code in payments_py/api/requests_api.py
def track_agent_sub_task(
    self, track_agent_sub_task: TrackAgentSubTaskDto
) -> Dict[str, Any]:
    """
    Tracks an agent sub task.

    This method is used by agent owners to track agent sub tasks for agent tasks.
    It records information about credit redemption, categorization tags, and processing descriptions.

    Args:
        track_agent_sub_task: The agent sub task data to track

    Returns:
        A promise that resolves to the result of the operation

    Raises:
        PaymentsError: If unable to track the agent sub task
    """
    body = {
        "agentRequestId": track_agent_sub_task.agent_request_id,
        "creditsToRedeem": track_agent_sub_task.credits_to_redeem or 0,
        "tag": track_agent_sub_task.tag,
        "description": track_agent_sub_task.description,
        "status": (
            track_agent_sub_task.status.value
            if track_agent_sub_task.status
            else None
        ),
    }

    options = self.get_backend_http_options("POST", body)
    url = f"{self.environment.backend}{API_URL_TRACK_AGENT_SUB_TASK}"
    response = requests.post(url, **options)

    if not response.ok:
        raise PaymentsError.internal(
            f"Unable to track agent sub task. {response.status_code} - {response.text}"
        )

    return response.json()

start_simulation_request

start_simulation_request(
    price_per_credit: float = 0.01,
    batch: bool = False,
    agent_name: str = None,
    plan_name: str = None,
) -> StartAgentRequest

This method simulates an agent request.

PARAMETER DESCRIPTION
price_per_credit

The price per credit in USD

TYPE: float DEFAULT: 0.01

batch

Whether the request is a batch request

TYPE: bool DEFAULT: False

agent_name

The name of the agent

TYPE: str DEFAULT: None

plan_name

The name of the plan

TYPE: str DEFAULT: None

RETURNS DESCRIPTION
StartAgentRequest

The information about the simulation of the request

Source code in payments_py/api/requests_api.py
def start_simulation_request(
    self,
    price_per_credit: float = 0.01,
    batch: bool = False,
    agent_name: str = None,
    plan_name: str = None,
) -> StartAgentRequest:
    """
    This method simulates an agent request.

    Args:
        price_per_credit: The price per credit in USD
        batch: Whether the request is a batch request
        agent_name: The name of the agent
        plan_name: The name of the plan

    Returns:
        The information about the simulation of the request
    """

    body = {
        "pricePerCredit": price_per_credit,
        "batch": batch,
    }
    if agent_name is not None:
        body["agentName"] = agent_name
    if plan_name is not None:
        body["planName"] = plan_name
    options = self.get_backend_http_options("POST", body)
    url = urljoin(self.environment.backend, API_URL_SIMULATE_AGENT_REQUEST)
    response = requests.post(url, **options)

    if not response.ok:
        raise PaymentsError.internal(
            f"Unable to start simulation request. {response.status_code} - {response.text}"
        )

    response_data = response.json()
    return StartAgentRequest(**response_data)

finish_simulation_request

finish_simulation_request(
    agent_request_id: str,
    margin_percent: float = 0.2,
    batch: bool = False,
) -> Dict[str, Any]

Simulates the redemption of credits for an agent request.

PARAMETER DESCRIPTION
agent_request_id

The unique identifier of the agent request.

TYPE: str

margin_percent

The margin percentage to apply. Defaults to 0.2.

TYPE: float DEFAULT: 0.2

batch

Whether the request is a batch request. Defaults to False.

TYPE: bool DEFAULT: False

RETURNS DESCRIPTION
Dict[str, Any]

A dictionary containing the result of the simulation, including the credits to redeem and the success status.

RAISES DESCRIPTION
PaymentsError

If unable to finish the simulation request.

Source code in payments_py/api/requests_api.py
def finish_simulation_request(
    self, agent_request_id: str, margin_percent: float = 0.2, batch: bool = False
) -> Dict[str, Any]:
    """
    Simulates the redemption of credits for an agent request.

    Args:
        agent_request_id: The unique identifier of the agent request.
        margin_percent: The margin percentage to apply. Defaults to 0.2.
        batch: Whether the request is a batch request. Defaults to False.

    Returns:
        A dictionary containing the result of the simulation, including the credits to redeem and the success status.

    Raises:
        PaymentsError: If unable to finish the simulation request.
    """

    body = {
        "agentRequestId": agent_request_id,
        "marginPercent": margin_percent,
        "batch": batch,
    }
    options = self.get_backend_http_options("POST", body)
    url = urljoin(self.environment.backend, API_URL_SIMULATE_REDEEM_AGENT_REQUEST)

    # Since this method is usually called immediately after the llm call
    # the request might not be immediately available on helicone, so we need to retry.
    max_retries = 3
    last_error = None

    for attempt in range(max_retries):
        try:
            response = requests.post(url, **options)
            if not response.ok:
                last_error = PaymentsError.internal(
                    f"Unable to finish simulation request. {response.status_code} - {response.text}"
                )
                if attempt < max_retries - 1:
                    time.sleep(1)
                    continue
                raise last_error
            return response.json()
        except requests.exceptions.RequestException as e:
            last_error = PaymentsError.internal(
                f"Unable to finish simulation request. Request failed: {str(e)}"
            )
            if attempt < max_retries - 1:
                time.sleep(1)
                continue
            raise last_error