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.
This guide explains how to purchase payment plans and check credit balances. These operations are typically performed by users who want to access AI agents.
Overview
The payment flow consists of:
- Discovering Plans: Browse available payment plans for agents
- Ordering Plans: Purchase a plan to receive credits
- Checking Balance: Monitor available credits and access status
Get Plan Balance
Subscribers can check their available credits for a specific plan:
import { Payments, EnvironmentName } from '@nevermined-io/payments'
// Initialize with subscriber's API key
const subscriberPayments = Payments.getInstance({
nvmApiKey: process.env.SUBSCRIBER_API_KEY!,
environment: 'sandbox' as EnvironmentName,
})
// Get balance for a plan
const balance = await subscriberPayments.plans.getPlanBalance(planId)
console.log(`Available credits: ${balance.balance}`)
console.log(`Is owner: ${balance.isOwner}`)
console.log(`Is subscriber: ${balance.isSubscriber}`)
Balance Response Structure
The balance response contains:
interface PlanBalance {
balance: string // Available credits as string
isOwner: boolean // True if you're the plan creator
isSubscriber: boolean // True if you have purchased this plan
}
Working with Balance
// Get balance
const balance = await subscriberPayments.plans.getPlanBalance(planId)
// Convert to BigInt for calculations
const creditsAvailable = BigInt(balance.balance)
// Check if sufficient credits
const creditsNeeded = 10n
if (creditsAvailable >= creditsNeeded) {
console.log('Sufficient credits available')
} else {
console.log(`Need ${creditsNeeded - creditsAvailable} more credits`)
}
Order a Plan
Subscribers purchase plans to receive credits:
Crypto Payment
For plans priced in cryptocurrency:
import { Payments, EnvironmentName } from '@nevermined-io/payments'
const subscriberPayments = Payments.getInstance({
nvmApiKey: process.env.SUBSCRIBER_API_KEY!,
environment: 'sandbox' as EnvironmentName,
})
// Order the plan
const orderResult = await subscriberPayments.plans.orderPlan(planId)
if (orderResult.success) {
console.log('Plan ordered successfully!')
console.log(`Transaction: ${orderResult.transaction}`)
} else {
console.error('Failed to order plan')
}
Fiat Payment (Stripe)
For plans priced in fiat currency, use orderFiatPlan to get a Stripe checkout URL:
const fiatResult = await subscriberPayments.plans.orderFiatPlan(planId)
if (fiatResult.checkoutUrl) {
console.log(`Complete payment at: ${fiatResult.checkoutUrl}`)
// Redirect the user to the Stripe checkout page
}
CLI
# Order a fiat plan (returns a Stripe checkout URL)
nvm plans order-fiat-plan <plan-id>
Note: When using X402 card-delegation tokens (nvm:card-delegation scheme), the payment is handled automatically through the delegated card — no separate checkout URL is needed. See Querying an Agent for details on card-delegation tokens.
Complete Purchase Flow
async function purchaseAndVerify(planId: string) {
const subscriberPayments = Payments.getInstance({
nvmApiKey: process.env.SUBSCRIBER_API_KEY!,
environment: 'sandbox',
})
// Check current balance
const beforeBalance = await subscriberPayments.plans.getPlanBalance(planId)
console.log(`Balance before: ${beforeBalance.balance} credits`)
// Order the plan
const orderResult = await subscriberPayments.plans.orderPlan(planId)
if (!orderResult.success) {
throw new Error('Failed to order plan')
}
console.log('Plan ordered successfully')
// Wait for credits to be allocated (blockchain settlement)
await new Promise(resolve => setTimeout(resolve, 5000))
// Check new balance
const afterBalance = await subscriberPayments.plans.getPlanBalance(planId)
console.log(`Balance after: ${afterBalance.balance} credits`)
}
Waiting for Balance Updates
After ordering a plan, credits are allocated on-chain, which may take a few seconds:
async function waitForCredits(
payments: Payments,
planId: string,
timeoutMs: number = 60000
): Promise<bigint> {
const startTime = Date.now()
const checkInterval = 2000 // Check every 2 seconds
while (Date.now() - startTime < timeoutMs) {
const balance = await payments.plans.getPlanBalance(planId)
const credits = BigInt(balance.balance)
if (credits > 0n) {
return credits
}
await new Promise(resolve => setTimeout(resolve, checkInterval))
}
throw new Error('Timeout waiting for credits')
}
// Usage
const credits = await waitForCredits(subscriberPayments, planId)
console.log(`Received ${credits} credits`)
Check Multiple Plan Balances
If a subscriber has multiple plans:
async function checkAllBalances(planIds: string[]) {
const subscriberPayments = Payments.getInstance({
nvmApiKey: process.env.SUBSCRIBER_API_KEY!,
environment: 'sandbox',
})
for (const planId of planIds) {
const balance = await subscriberPayments.plans.getPlanBalance(planId)
console.log(`Plan ${planId}: ${balance.balance} credits`)
}
}
await checkAllBalances([planId1, planId2, planId3])
Stripe Checkout Integration
Stripe checkout for fiat-priced plans is managed through the Nevermined App dashboard.
Visit nevermined.app to configure Stripe payments for your plans.
Before ordering, subscribers might want to view plan details:
// Get plan details
const plan = await subscriberPayments.plans.getPlan(planId)
console.log(`Plan: ${plan.name}`)
console.log(`Description: ${plan.description}`)
console.log(`Price: ${plan.price}`)
console.log(`Credits: ${plan.credits}`)
// Check if already purchased
const balance = await subscriberPayments.plans.getPlanBalance(planId)
if (balance.isSubscriber && BigInt(balance.balance) > 0n) {
console.log('Already purchased with available credits')
} else {
console.log('Need to order plan')
}
Complete Example: Purchase Flow with UI
import { Payments, EnvironmentName } from '@nevermined-io/payments'
class PlanPurchaseManager {
private payments: Payments
constructor(apiKey: string, environment: EnvironmentName) {
this.payments = Payments.getInstance({
nvmApiKey: apiKey,
environment,
})
}
async checkBalance(planId: string): Promise<bigint> {
const balance = await this.payments.plans.getPlanBalance(planId)
return BigInt(balance.balance)
}
async purchasePlan(planId: string): Promise<boolean> {
try {
// Get plan details
const plan = await this.payments.plans.getPlan(planId)
console.log(`Purchasing: ${plan.name}`)
// Check if already subscribed
const currentBalance = await this.checkBalance(planId)
if (currentBalance > 0n) {
console.log(`Already have ${currentBalance} credits`)
return true
}
// Order the plan
const orderResult = await this.payments.plans.orderPlan(planId)
if (!orderResult.success) {
throw new Error('Order failed')
}
console.log(`Order successful: ${orderResult.transaction}`)
// Wait for credits
const credits = await this.waitForCredits(planId)
console.log(`Received ${credits} credits`)
return true
} catch (error) {
console.error('Purchase failed:', error)
return false
}
}
private async waitForCredits(
planId: string,
timeoutMs: number = 60000
): Promise<bigint> {
const startTime = Date.now()
const checkInterval = 2000
while (Date.now() - startTime < timeoutMs) {
const credits = await this.checkBalance(planId)
if (credits > 0n) return credits
await new Promise(resolve => setTimeout(resolve, checkInterval))
}
throw new Error('Timeout waiting for credits')
}
}
// Usage
const manager = new PlanPurchaseManager(
process.env.SUBSCRIBER_API_KEY!,
'sandbox'
)
const success = await manager.purchasePlan(planId)
if (success) {
const balance = await manager.checkBalance(planId)
console.log(`Ready to use agent with ${balance} credits`)
}
Best Practices
- Check Balance First: Always check existing balance before ordering
- Wait for Settlement: Allow time for on-chain credit allocation after purchase
- Handle Errors: Wrap order operations in try-catch blocks
- User Feedback: Provide clear feedback during the purchase process
- Balance Monitoring: Check balance before each agent request
- Stripe Redirects: Use absolute URLs for Stripe success/cancel URLs
Source References:
src/api/plans-api.ts (orderPlan, getPlanBalance methods)
tests/e2e/test_payments_e2e.test.ts (ordering and balance verification)