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
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions