Skip to content

Migrate tutorial agents from JWT flow to x402 access tokens #29

@r-marques

Description

@r-marques

Summary

Update all tutorial agents to use the new x402 access token flow instead of the legacy JWT-based flow. The x402 implementation provides a simpler developer experience with delegated session keys that enable auto-ordering of credits.

Important: Tutorials should follow the x402 transport specifications for each integration type.

Background

The Nevermined API has migrated from the old protocol module (initializeAgentRequest / redeemCredits with JWT tokens) to a new x402-based solution. The SDKs (@nevermined-io/payments and payments-py) have been updated with the necessary functionality.

Key x402 Advantages

  • No pre-purchase required: Subscribers don't need to check balance or order plans in advance
  • Delegated permissions: x402 tokens include "order" (auto top-up) and "burn" (redeem credits) session keys
  • Smart Account integration: Uses ERC-4337 Account Abstraction for seamless transactions

x402 Transport Specifications

Each tutorial type should follow the corresponding x402 transport spec:

Tutorial Type x402 Transport Spec
HTTP (financial-agent, medical-agent) specs/transports-v2/http.md
A2A (a2a-agent-client-example) specs/transports-v2/a2a.md
MCP (weather-mcp, weather-mcp-py) specs/transports-v2/mcp.md

Migration Details

Old Flow (to be replaced)

// Client
const credentials = await payments.agents.getAgentAccessToken(planId, agentId);

// Server
const agentRequest = await payments.requests.startProcessingRequest(agentId, authHeader, url, httpVerb);
if (!agentRequest.balance.isSubscriber || agentRequest.balance.balance < 1n) {
  return res.status(402).json({ error: "Payment Required" });
}
await payments.requests.redeemCreditsFromRequest(requestId, token, credits);

New x402 Flow

// Client - much simpler, no balance check needed
const result = await payments.x402.getX402AccessToken(planId, agentId);
const x402Token = result.accessToken;

// Server
import { decodeAccessToken } from '@nevermined-io/payments'

const x402Token = authHeader.replace(/^Bearer\s+/i, "");
const decoded = decodeAccessToken(x402Token);

const verification = await payments.facilitator.verifyPermissions({
  planId,
  x402AccessToken: x402Token,
  subscriberAddress: decoded.subscriberAddress,
  maxAmount: BigInt(expectedCredits),
});

if (!verification.success) {
  return res.status(402).json({ error: "Payment Required" });
}

// ... do work ...

const settlement = await payments.facilitator.settlePermissions({
  planId,
  x402AccessToken: x402Token,
  subscriberAddress: decoded.subscriberAddress,
  maxAmount: BigInt(actualCreditsUsed),
});

Tutorials to Update

Phase 1: HTTP Tutorials (follow http.md)

  • financial-agent/agent/index_nevermined.ts - Server-side
  • financial-agent/client/index_nevermined.ts - Client-side
  • medical-agent/agent/index_nevermined.ts - Server-side
  • medical-agent/client/index_nevermined.ts - Client-side

Phase 2: A2A Tutorial (follow a2a.md)

  • a2a-examples/a2a-agent-client-example/ - Full migration

Phase 3: MCP Tutorials (follow mcp.md)

  • mcp-examples/weather-mcp/ - TypeScript MCP server
  • mcp-examples/weather-mcp-py/ - Python MCP server

Reference Code & E2E Tests

TypeScript SDK (@nevermined-io/payments)

Python SDK (payments-py)

API Implementation (nvm-monorepo)

  • Controller spec: apps/api/src/x402/x402.controller.external.spec.ts
  • Service: apps/api/src/x402/x402.service.ts
  • Controller: apps/api/src/x402/x402.controller.ts

Key SDK Methods

Subscriber (Client-side)

Method TypeScript Python
Get x402 token payments.x402.getX402AccessToken(planId, agentId) payments.x402.get_x402_access_token(plan_id, agent_id)

Agent (Server-side)

Method TypeScript Python
Decode token decodeAccessToken(token) decode_access_token(token)
Verify payments.facilitator.verifyPermissions({...}) payments.facilitator.verify_permissions(...)
Settle payments.facilitator.settlePermissions({...}) payments.facilitator.settle_permissions(...)

Optional Parameters

The getX402AccessToken method supports optional parameters:

  • redemptionLimit: Max number of interactions allowed
  • orderLimit: Max spend limit in token units (wei)
  • expiration: ISO 8601 expiration date (e.g., "2025-02-01T10:00:00Z")

Acceptance Criteria

  • All tutorials use x402 flow instead of JWT flow
  • Tutorials follow the corresponding x402 transport specs (HTTP, A2A, MCP)
  • Client-side code is simplified (no balance checks or pre-purchase)
  • Server-side uses facilitator.verifyPermissions() and settlePermissions()
  • README files updated with new flow explanation
  • Environment variable documentation updated
  • All tutorials tested end-to-end

Related Documentation

Metadata

Metadata

Labels

javascriptPull requests that update javascript codepythonPull requests that update python codetutorials

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions