Looking for framework-specific implementations?
Basic validation (framework-agnostic)
At a minimum, validation has three steps:- Extract a Bearer token from the
Authorizationheader - Validate it against the request body
- Return
402 Payment Required(optionally includingplans) when missing/invalid
- TypeScript
- Python
Copy
Ask AI
import { Payments } from '@nevermined-io/payments'
const payments = Payments.getInstance({
nvmApiKey: process.env.NVM_API_KEY!,
environment: 'sandbox'
})
export async function validateRequest(token: string, body: unknown) {
const result = await payments.requests.isValidRequest(token, body)
return {
isValid: result.isValid,
balance: result.balance,
reason: result.reason
}
}
// Pseudo-usage
// - Extract token from Authorization: Bearer <token>
// - Call validateRequest(token, body)
// - If invalid, return 402
Copy
Ask AI
import os
from payments_py import Payments, PaymentOptions
payments = Payments.get_instance(
PaymentOptions(nvm_api_key=os.environ['NVM_API_KEY'], environment='sandbox')
)
async def validate_request(token: str, body: dict) -> dict:
result = await payments.requests.is_valid_request(token, body)
return {
'is_valid': result['isValid'],
'balance': result['balance'],
'reason': result.get('reason')
}
# Pseudo-usage:
# - Extract token from Authorization: Bearer <token>
# - Call await validate_request(token, body)
# - If invalid, return 402
Validation with minimum credits
Check that the user has enough credits for the operation:- TypeScript
- Python
Copy
Ask AI
export async function validateWithMinimum(
token: string,
body: unknown,
minCredits: number
) {
const result = await payments.requests.isValidRequest(token, body)
if (!result.isValid) {
return { valid: false, reason: 'invalid_token' as const }
}
if (result.balance < minCredits) {
return {
valid: false,
reason: 'insufficient_credits' as const,
required: minCredits,
available: result.balance
}
}
return { valid: true, balance: result.balance }
}
// Example: expensive operation
const validation = await validateWithMinimum(token, body, 10)
if (!validation.valid) {
// return 402
}
Copy
Ask AI
async def validate_with_minimum(token: str, body: dict, min_credits: int) -> dict:
result = await payments.requests.is_valid_request(token, body)
if not result['isValid']:
return {'valid': False, 'reason': 'invalid_token'}
if result['balance'] < min_credits:
return {
'valid': False,
'reason': 'insufficient_credits',
'required': min_credits,
'available': result['balance']
}
return {'valid': True, 'balance': result['balance']}
# Example: expensive operation
validation = await validate_with_minimum(token, body, 10)
if not validation['valid']:
# return 402
pass
Validation response handling
Handle all possible validation outcomes:- TypeScript
- Python
Copy
Ask AI
async function handleValidation(token: string, body: any) {
try {
const result = await payments.requests.isValidRequest(token, body)
if (!result.isValid) {
// Determine specific error
switch (result.reason) {
case 'TOKEN_EXPIRED':
return {
status: 402,
error: 'Access token has expired',
code: 'TOKEN_EXPIRED',
action: 'refresh_token'
}
case 'INSUFFICIENT_BALANCE':
return {
status: 402,
error: 'Insufficient credits',
code: 'INSUFFICIENT_BALANCE',
action: 'purchase_credits'
}
case 'PLAN_EXPIRED':
return {
status: 402,
error: 'Plan has expired',
code: 'PLAN_EXPIRED',
action: 'renew_plan'
}
default:
return {
status: 402,
error: 'Invalid token',
code: 'INVALID_TOKEN',
action: 'get_new_token'
}
}
}
return { status: 200, balance: result.balance }
} catch (error) {
console.error('Validation error:', error)
return {
status: 500,
error: 'Validation service unavailable',
code: 'SERVICE_ERROR'
}
}
}
Copy
Ask AI
async def handle_validation(token: str, body: dict) -> dict:
try:
result = await payments.requests.is_valid_request(token, body)
if not result['isValid']:
reason = result.get('reason', 'UNKNOWN')
error_map = {
'TOKEN_EXPIRED': {
'status': 402,
'error': 'Access token has expired',
'code': 'TOKEN_EXPIRED',
'action': 'refresh_token'
},
'INSUFFICIENT_BALANCE': {
'status': 402,
'error': 'Insufficient credits',
'code': 'INSUFFICIENT_BALANCE',
'action': 'purchase_credits'
},
'PLAN_EXPIRED': {
'status': 402,
'error': 'Plan has expired',
'code': 'PLAN_EXPIRED',
'action': 'renew_plan'
}
}
return error_map.get(reason, {
'status': 402,
'error': 'Invalid token',
'code': 'INVALID_TOKEN',
'action': 'get_new_token'
})
return {'status': 200, 'balance': result['balance']}
except Exception as e:
print(f'Validation error: {e}')
return {
'status': 500,
'error': 'Validation service unavailable',
'code': 'SERVICE_ERROR'
}
Caching validation results
For high-traffic endpoints, cache validation briefly:- TypeScript
- Python
Copy
Ask AI
import { LRUCache } from 'lru-cache'
const validationCache = new LRUCache<string, any>({
max: 1000,
ttl: 1000 * 30 // 30 seconds
})
async function validateWithCache(token: string, body: any) {
// Create cache key from token hash
const cacheKey = hashToken(token)
const cached = validationCache.get(cacheKey)
if (cached) {
return cached
}
const result = await payments.requests.isValidRequest(token, body)
if (result.isValid) {
validationCache.set(cacheKey, result)
}
return result
}
function hashToken(token: string): string {
return crypto.createHash('sha256').update(token).digest('hex').slice(0, 16)
}
Copy
Ask AI
from datetime import datetime, timedelta
import hashlib
validation_cache = {}
CACHE_TTL = timedelta(seconds=30)
async def validate_with_cache(token: str, body: dict) -> dict:
cache_key = hash_token(token)
# Check cache
if cache_key in validation_cache:
cached, timestamp = validation_cache[cache_key]
if datetime.now() - timestamp < CACHE_TTL:
return cached
result = await payments.requests.is_valid_request(token, body)
if result['isValid']:
validation_cache[cache_key] = (result, datetime.now())
return result
def hash_token(token: str) -> str:
return hashlib.sha256(token.encode()).hexdigest()[:16]