{"id":"d70b71e4-282d-4b13-aad4-001109602b98","entityType":"agent","slug":"clawhub-nevermined-io-nevermined","name":"Nevermined Payments","canonicalUrl":"https://www.xpersona.co/agent/clawhub-nevermined-io-nevermined","canonicalPath":"/agent/clawhub-nevermined-io-nevermined","generatedAt":"2026-10-10T21:44:14.224Z","source":"CLAWHUB","claimStatus":"UNCLAIMED","verificationTier":"NONE","summary":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"medium","updatedAt":"2026-10-10T16:20:03.897Z","emptyReason":null},"description":"Use when an AI agent must operate on Nevermined autonomously — purchase a payment plan via the x402 protocol (crypto or card), enroll a card and create a spending delegation, obtain a Nevermined API key, register a payment plan or AI agent, or check its credits (as a buyer) or revenue (as a seller) — and when adding x402 payment protection to a TypeScript or Python agent (Express, FastAPI, MCP, Google A2A, Strands, LangChain / LangGraph). Covers the @nevermined-io/payments and payments-py SDKs and the Nevermined REST API.","descriptionLabel":"Source description","evidenceSummary":"Capability contract not published. No trust telemetry is available yet. 1.3K downloads reported by the source. Last updated 10/10/2026.","installCommand":"clawhub skill install s17beb0b7q3geaakdyrsav6nq188t5nd:nevermined","sourceUrl":"https://clawhub.ai/nevermined-io/nevermined","homepage":"https://clawhub.ai/nevermined-io/skills/nevermined","primaryLinks":[{"label":"View on ClawHub","url":"https://clawhub.ai/nevermined-io/nevermined","kind":"source"},{"label":"Homepage","url":"https://clawhub.ai/nevermined-io/skills/nevermined","kind":"homepage"}],"safetyScore":84,"overallRank":62,"popularityScore":63,"trustScore":null,"claimedByName":null,"isOwner":false,"seoDescription":"Nevermined Payments technical dossier on Xpersona with agent coverage, OPENCLEW support, and live trust metadata."},"coverage":{"evidence":{"source":"public-profile","verified":false,"confidence":"medium","updatedAt":"2026-10-10T16:20:03.897Z","emptyReason":null},"protocols":[{"protocol":"OPENCLEW","label":"OpenClaw","status":"self-declared","notes":"Declared in the public agent profile."}],"capabilities":[],"verifiedCount":0,"selfDeclaredCount":1,"capabilityMatrix":{"rows":[{"key":"OPENCLEW","type":"protocol","support":"unknown","confidenceSource":"profile","notes":"Listed on profile"}],"flattenedTokens":"protocol:OPENCLEW|unknown|profile"}},"adoption":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"medium","updatedAt":"2026-10-10T16:20:03.897Z","emptyReason":null},"stars":null,"forks":null,"downloads":1341,"packageName":null,"latestVersion":"1.0.10","tractionLabel":"1.3K downloads"},"release":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"medium","updatedAt":"2026-10-10T16:20:03.823Z","emptyReason":null},"lastUpdatedAt":"2026-10-10T16:20:03.897Z","lastCrawledAt":"2026-10-10T16:20:03.823Z","lastIndexedAt":null,"nextCrawlAt":"2026-10-11T16:20:03.823Z","lastVerifiedAt":null,"highlights":[{"version":"1.0.10","createdAt":"2026-09-25T17:34:49.120Z","changelog":"- Verified against latest SDKs: upgraded references to @nevermined-io/payments@1.13.0 and payments-py@1.18.0. - Added explicit mention of LangChain / LangGraph integrations. - Updated all dates and version markers to 0.5.2 (2026-09-25). - Minor copy improvements in instructions and warning banners for clarity. - Removed duplicate or redundant material and outdated version references. - Removed the skill-card.md file; documentation is now consolidated.","fileCount":15,"zipByteSize":60341},{"version":"1.0.9","createdAt":"2026-09-11T15:25:19.877Z","changelog":"nevermined 1.0.9 - Documentation updated in SKILL.md and several reference files for improved clarity and coverage. - Reference docs enhanced: `autonomous-operations.md`, `client-integration.md`, `express-integration.md`, and `mcp-paywall.md` revised. - The deprecated or outdated file `skill-card.md` was removed. - No user-facing functionality was changed; this is a documentation and maintenance release.","fileCount":15,"zipByteSize":60378},{"version":"1.0.8","createdAt":"2026-09-11T09:15:54.051Z","changelog":"nevermined 1.0.8 - Updated documentation in `references/autonomous-operations.md`. - Removed obsolete file `skill-card.md`.","fileCount":15,"zipByteSize":59135},{"version":"1.0.7","createdAt":"2026-07-30T16:02:12.518Z","changelog":"nevermined 1.0.7 - Documentation updated: SKILL.md was revised with the latest integration instructions and reference links. - Outdated or redundant file removed: skill-card.md no longer included.","fileCount":15,"zipByteSize":58884},{"version":"1.0.6","createdAt":"2026-07-30T11:27:16.272Z","changelog":"# nevermined 1.0.6 Changelog - Documentation updates to `SKILL.md`. - Removed deprecated `skill-card.md` file. - No changes to code or interfaces.","fileCount":15,"zipByteSize":58924},{"version":"1.0.5","createdAt":"2026-07-29T15:48:26.622Z","changelog":"nevermined v1.0.5 - Documentation (SKILL.md) updated; clarifies usage patterns and REST integration details. - File skill-card.md removed to streamline sources and reduce redundancy. - No changes to API, environment variables, or SDK usage. - Existing integrations are unaffected.","fileCount":15,"zipByteSize":58881},{"version":"1.0.4","createdAt":"2026-07-24T13:28:37.301Z","changelog":"nevermined 1.0.4 - Added a customer onboarding reference: `references/customer-onboarding.md`. - Updated main documentation (`SKILL.md`) to reference customer onboarding material. - Removed deprecated file: `skill-card.md`.","fileCount":15,"zipByteSize":58972},{"version":"1.0.3","createdAt":"2026-07-22T13:39:07.906Z","changelog":"- Removed the file: skill-card.md. - Made minor edits to the SKILL.md, notably updating a changelog link to https://nevermined.ai/docs/development-guide/api-changelog. - No functional or interface changes to the skill itself. - The rest of the SKILL.md content remains unchanged.","fileCount":14,"zipByteSize":56555}]},"execution":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"low","updatedAt":null,"emptyReason":"No published capability contract is available yet."},"installCommand":"clawhub skill install s17beb0b7q3geaakdyrsav6nq188t5nd:nevermined","setupComplexity":"low","setupSteps":["Install using `clawhub skill install s17beb0b7q3geaakdyrsav6nq188t5nd:nevermined` in an isolated environment before connecting it to live workloads.","No published capability contract is available yet, so validate auth and request/response behavior manually.","Review the upstream CLAWHUB listing at https://clawhub.ai/nevermined-io/nevermined before using production credentials."],"contract":{"contractStatus":"missing","authModes":[],"requires":[],"forbidden":[],"supportsMcp":false,"supportsA2a":false,"supportsStreaming":false,"inputSchemaRef":null,"outputSchemaRef":null,"dataRegion":null,"contractUpdatedAt":null,"sourceUpdatedAt":null,"freshnessSeconds":null},"invocationGuide":{"preferredApi":{"snapshotUrl":"https://www.xpersona.co/api/v1/agents/clawhub-nevermined-io-nevermined/snapshot","contractUrl":"https://www.xpersona.co/api/v1/agents/clawhub-nevermined-io-nevermined/contract","trustUrl":"https://www.xpersona.co/api/v1/agents/clawhub-nevermined-io-nevermined/trust"},"curlExamples":["curl -s \"https://www.xpersona.co/api/v1/agents/clawhub-nevermined-io-nevermined/snapshot\"","curl -s \"https://www.xpersona.co/api/v1/agents/clawhub-nevermined-io-nevermined/contract\"","curl -s \"https://www.xpersona.co/api/v1/agents/clawhub-nevermined-io-nevermined/trust\""],"jsonRequestTemplate":{"query":"summarize this repo","constraints":{"maxLatencyMs":2000,"protocolPreference":["OPENCLEW"]}},"jsonResponseTemplate":{"ok":true,"result":{"summary":"...","confidence":0.9},"meta":{"source":"CLAWHUB","generatedAt":"2026-10-10T21:44:14.222Z"}},"retryPolicy":{"maxAttempts":3,"backoffMs":[500,1500,3500],"retryableConditions":["HTTP_429","HTTP_503","NETWORK_TIMEOUT"]}},"endpoints":{"dossierUrl":"https://www.xpersona.co/api/v1/agents/clawhub-nevermined-io-nevermined/dossier","snapshotUrl":"https://www.xpersona.co/api/v1/agents/clawhub-nevermined-io-nevermined/snapshot","contractUrl":"https://www.xpersona.co/api/v1/agents/clawhub-nevermined-io-nevermined/contract","trustUrl":"https://www.xpersona.co/api/v1/agents/clawhub-nevermined-io-nevermined/trust"}},"reliability":{"evidence":{"source":"runtime-metrics","verified":false,"confidence":"low","updatedAt":null,"emptyReason":"No trust, reliability, or runtime telemetry is available."},"trust":{"status":"unavailable","handshakeStatus":"UNKNOWN","verificationFreshnessHours":null,"reputationScore":null,"p95LatencyMs":null,"successRate30d":null,"fallbackRate":null,"attempts30d":null,"trustUpdatedAt":null,"trustConfidence":"unknown","sourceUpdatedAt":null,"freshnessSeconds":null},"decisionGuardrails":{"doNotUseIf":["Contract metadata is missing or unavailable for deterministic execution."],"safeUseWhen":[],"riskFlags":["missing_or_unavailable_contract","trust_data_unavailable","schema_references_missing"],"operationalConfidence":"low"},"executionMetrics":{"observedLatencyMsP50":null,"observedLatencyMsP95":null,"estimatedCostUsd":null,"uptime30d":null,"rateLimitRpm":null,"rateLimitBurst":null,"lastVerifiedAt":null,"verificationSource":null},"runtimeMetrics":{"successRate":null,"avgLatencyMs":null,"avgCostUsd":null,"hallucinationRate":null,"retryRate":null,"disputeRate":null,"p50Latency":null,"p95Latency":null,"lastUpdated":null}},"benchmarks":{"evidence":{"source":"no-benchmark-data","verified":false,"confidence":"low","updatedAt":null,"emptyReason":"No benchmark suites or observed failure patterns are available."},"suites":[],"failurePatterns":[]},"artifacts":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"medium","updatedAt":"2026-10-10T16:20:03.897Z","emptyReason":null},"readme":"Skill: Nevermined Payments\n\nOwner: nevermined-io\n\nSummary: Use when an AI agent must operate on Nevermined autonomously — purchase a payment plan via the x402 protocol (crypto or card), enroll a card and create a spending delegation, obtain a Nevermined API key, register a payment plan or AI agent, or check its credits (as a buyer) or revenue (as a seller) — and when adding x402 payment protection to a TypeScript or Python agent (Express, FastAPI, MCP, Google A2A, Strands, LangChain / LangGraph). Covers the @nevermined-io/payments and payments-py SDKs and the Nevermined REST API.\n\nTags: latest:1.0.10\n\nVersion history:\n\nv1.0.10 | 2026-09-25T17:34:49.120Z | auto\n\n- Verified against latest SDKs: upgraded references to @nevermined-io/payments@1.13.0 and payments-py@1.18.0.\n- Added explicit mention of LangChain / LangGraph integrations.\n- Updated all dates and version markers to 0.5.2 (2026-09-25).\n- Minor copy improvements in instructions and warning banners for clarity.\n- Removed duplicate or redundant material and outdated version references.\n- Removed the skill-card.md file; documentation is now consolidated.\n\nv1.0.9 | 2026-09-11T15:25:19.877Z | auto\n\nnevermined 1.0.9\n\n- Documentation updated in SKILL.md and several reference files for improved clarity and coverage.\n- Reference docs enhanced: `autonomous-operations.md`, `client-integration.md`, `express-integration.md`, and `mcp-paywall.md` revised.\n- The deprecated or outdated file `skill-card.md` was removed.\n- No user-facing functionality was changed; this is a documentation and maintenance release.\n\nv1.0.8 | 2026-09-11T09:15:54.051Z | auto\n\nnevermined 1.0.8\n\n- Updated documentation in `references/autonomous-operations.md`.\n- Removed obsolete file `skill-card.md`.\n\nv1.0.7 | 2026-07-30T16:02:12.518Z | auto\n\nnevermined 1.0.7\n\n- Documentation updated: SKILL.md was revised with the latest integration instructions and reference links.\n- Outdated or redundant file removed: skill-card.md no longer included.\n\nv1.0.6 | 2026-07-30T11:27:16.272Z | auto\n\n# nevermined 1.0.6 Changelog\n\n- Documentation updates to `SKILL.md`.\n- Removed deprecated `skill-card.md` file.\n- No changes to code or interfaces.\n\nv1.0.5 | 2026-07-29T15:48:26.622Z | auto\n\nnevermined v1.0.5\n\n- Documentation (SKILL.md) updated; clarifies usage patterns and REST integration details.\n- File skill-card.md removed to streamline sources and reduce redundancy.\n- No changes to API, environment variables, or SDK usage.\n- Existing integrations are unaffected.\n\nv1.0.4 | 2026-07-24T13:28:37.301Z | auto\n\nnevermined 1.0.4\n\n- Added a customer onboarding reference: `references/customer-onboarding.md`.\n- Updated main documentation (`SKILL.md`) to reference customer onboarding material.\n- Removed deprecated file: `skill-card.md`.\n\nv1.0.3 | 2026-07-22T13:39:07.906Z | auto\n\n- Removed the file: skill-card.md.\n- Made minor edits to the SKILL.md, notably updating a changelog link to https://nevermined.ai/docs/development-guide/api-changelog.\n- No functional or interface changes to the skill itself.\n- The rest of the SKILL.md content remains unchanged.\n\nv1.0.2 | 2026-06-23T13:39:22.687Z | auto\n\n- Removed the file: skill-card.md\n- Updated SKILL.md with current content; no functional or documented changes detected in the main skill description or flow.\n- No new features or interface changes for end users.\n\nv1.0.1 | 2026-06-18T15:20:10.168Z | auto\n\nnevermined v1.0.1\n\n- Updated SDK version references in documentation (`@nevermined-io/payments@1.9.0`, `payments-py@1.15.1`)\n- Maintenance refresh of API/SDK doc links and minor dates\n- Removed outdated `skill-card.md` file\n- Improved clarity in references to buyer and seller operations and API environment settings\n\nv1.0.0 | 2026-06-17T08:39:05.893Z | auto\n\nNevermined Payments Skill 1.0.0\n\n- Initial release of the nevermined-payments skill (version 0.5.0).\n- Provides detailed REST and SDK workflows for autonomous agent payments, including buying plans, card enrollment, delegations, API key management, and revenue/credits queries.\n- Covers both agent (REST) and developer (SDK for TypeScript/Python) modes.\n- Includes full environment setup, x402 protocol summary, and guidance for API version pinning.\n- References documentation for payload details and advanced operations.\n- Suitable for integrating x402 payment protection into TypeScript or Python AI agents.\n\nArchive index:\n\nArchive v1.0.10: 15 files, 60341 bytes\n\nFiles: references/a2a-integration.md (8982b), references/autonomous-operations.md (15060b), references/client-integration.md (14067b), references/customer-onboarding.md (3956b), references/express-integration.md (4419b), references/fastapi-integration.md (7511b), references/langchain-integration.md (15599b), references/mcp-paywall.md (9636b), references/payment-plans.md (9490b), references/seller-operations.md (5653b), references/strands-integration.md (6770b), references/x402-protocol.md (6640b), skill-card.md (2237b), SKILL.md (47432b), _meta.json (130b)\n\nFile v1.0.10:SKILL.md\n\n---\nname: nevermined-payments\nversion: \"0.5.2\"\nlastUpdated: \"2026-09-25\"\ndescription: >\n  Use when an AI agent must operate on Nevermined autonomously — purchase a payment\n  plan via the x402 protocol (crypto or card), enroll a card and create a spending\n  delegation, obtain a Nevermined API key, register a payment plan or AI agent, or\n  check its credits (as a buyer) or revenue (as a seller) — and when adding x402\n  payment protection to a TypeScript or Python agent (Express, FastAPI, MCP, Google\n  A2A, Strands, LangChain / LangGraph). Covers the @nevermined-io/payments and payments-py SDKs and the\n  Nevermined REST API.\nmetadata:\n  openclaw:\n    primaryEnv: NVM_API_KEY\n    requires:\n      env:\n        - NVM_API_KEY\n    envVars:\n      - name: NVM_API_KEY\n        required: true\n        description: >\n          Nevermined API key used by the SDK, REST API, and CLI. Format\n          `sandbox:...` for the sandbox environment, `live:...` for production.\n          Issued from https://nevermined.app under API Keys.\n---\n\n# Nevermined Payments Integration\n\n> **Skill version**: 0.5.2 | **Last updated**: 2026-09-25 | **Canonical source (always latest):** https://github.com/nevermined-io/docs/tree/main/skills/nevermined-payments\n>\n> **Use the latest version.** This skill changes often. If you have an installed or cached copy, compare its **Last updated** date with the canonical source above and refresh it if older — an out-of-date copy can be missing whole flows. Unless a specific version is requested, work from the latest.\n>\n> Verified against the live sandbox API (`https://api.sandbox.nevermined.app/api/v1/rest/docs-json`); the cited SDK calls were checked against `@nevermined-io/payments@1.13.0` and `payments-py@1.18.0` — install the latest release of each.\n\n## Overview\n\nNevermined provides financial rails for AI agents — real-time monetization, access control, and payments. This skill covers **two modes**, and most tasks fall cleanly into one:\n\n| Mode | You are… | Lead interface | Use when the goal is… |\n|---|---|---|---|\n| **🅐 Operate as an autonomous agent** | an agent **acting on its own behalf** at runtime | **REST** (works with no SDK install) | buy a plan, enroll a card + delegation, get an API key, register a plan/agent, check credits (buyer) or revenue (seller) |\n| **🅑 Add payments to your code** | a developer **wiring payments into an agent** so it can **receive** payments | **SDK** (TypeScript / Python) | protect Express/FastAPI/MCP/A2A/Strands endpoints behind a plan |\n\nIf you are an autonomous agent that needs to **pay, enroll, register, or report**, start at **Track A — Operate as an autonomous agent**. If you are building a service that needs to **charge** callers, jump to **Track B — Add payments to your code**.\n\n### How payments work (x402 in one minute)\n\nNevermined uses the **x402 protocol** (HTTP `402 Payment Required`). A buyer acquires an **access token** authorizing a spend, then **settles** it — which charges the payment method, mints, and burns credits. The same token can be sent to a protected agent in the `payment-signature` header; the agent verifies and settles for you.\n\nTwo payment **schemes** exist:\n\n| Scheme | Pays with | `network` value |\n|---|---|---|\n| `nvm:erc4337` | Crypto stablecoins (USDC / EURC) via account-abstraction delegation | CAIP-2 chain id — `eip155:84532` (sandbox / Base Sepolia), `eip155:8453` (live / Base Mainnet) |\n| `nvm:card-delegation` | A card on file via Stripe / Braintree / Visa delegation | `stripe`, `braintree`, or `visa` |\n\nThree HTTP headers carry x402 data: `payment-signature` (client→server, the token), `payment-required` (server→client on 402, base64 JSON), `payment-response` (server→client on 200, base64 settlement receipt).\n\n---\n\n# Track A — Operate as an autonomous agent\n\nThis is a **REST runbook**: every step (A1–A8 below) is a plain HTTPS call you can make with `curl` or any HTTP client — **no SDK install required**. Each flow ends with the equivalent SDK one-liner if you prefer typed calls.\n\n**Where the full detail lives.** Every flow is documented inline below (A1–A8). The complete request/response bodies are in the reference files alongside this skill — read the matching one when you need exact payloads:\n\n| You need… | Read |\n|---|---|\n| API keys, **card enrollment + embedded session + delegation**, payment methods, x402 buy/settle, buyer status — full REST bodies | `references/autonomous-operations.md` (card flow = **§3**, x402 buy = **§4**) |\n| Seller revenue / analytics queries (A7) | `references/seller-operations.md` |\n| Onboard your own customers (white-label, A8) | `references/customer-onboarding.md` |\n| Plan registration + the plan-type matrix (A6) | `references/payment-plans.md` |\n| Subscriber-side SDK patterns | `references/client-integration.md` |\n\n> **Design principle — minimal human interaction.** A human is needed for **at most two one-time setup steps — often just one**:\n> 1. **Get your first API key** (a human signs in once) — always required, and\n> 2. **Enroll a card** (a human enters card details in a browser — required by PCI) — **only if you pay by card**; the stablecoin path skips this entirely.\n>\n> **Everything else is fully programmatic** and reusable: checking payment methods, creating delegations, purchasing, settling, registering plans/agents, and reading buyer/seller status. Store the API key and any `delegationId` and reuse them.\n\n## A0 · Environment\n\nPick the environment and use its **exact base URL** for every call. State it explicitly to yourself — do not infer it from anything else.\n\n| Environment | API base URL | App (human steps) | Card enrollment UI | Network | API key prefix |\n|---|---|---|---|---|---|\n| **sandbox** (test money) | `https://api.sandbox.nevermined.app` | `https://nevermined.app` | `https://embed.nevermined.app` | Base Sepolia `eip155:84532` | `sandbox:` |\n| **live** (real money) | `https://api.live.nevermined.app` | `https://nevermined.app` | `https://embed.nevermined.app` | Base Mainnet `eip155:8453` | `live:` |\n\n- **Auth:** send your key as `Authorization: Bearer <NVM_API_KEY>` on every call (a few read-only endpoints — e.g. `GET /protocol/plans/{id}` and `GET /protocol/agents/{id}/plans` — are public, but the header is harmless there).\n- **Never log or persist secrets in the clear:** API keys, `delegationId`, and `paymentMethodId` arrive as query-string params on your `127.0.0.1` callback (see A1/A3). Your callback server must not log the request line, and you should keep the key in a secret store — query strings are the most-logged part of any request (access logs, shell history, process args).\n- **Discover the API surface:** `GET {API_BASE}/api/v1/rest/docs-json` returns the OpenAPI JSON. **Heads-up — it is not exhaustive:** several agent-facing endpoints are served but **deliberately omitted from `docs-json`**, notably `POST /embed/session` (card enrollment), the `delegation/*` routes, and `organizations/{orgId}/analytics/*`. Don't conclude an endpoint doesn't exist because it's absent from the OpenAPI — **use the exact paths documented in this skill directly**. (To confirm one is live, send the request: a `401`/`400` means it exists; only `404` means it doesn't.)\n- **Default to `sandbox`** unless the human explicitly asks for `live` — `live` moves real money.\n- **Pin the API version:** send `Nevermined-Version: <MAJOR.MINOR>` on every direct REST call so platform releases can't change the wire shape under you. Discover the supported range with `GET {API_BASE}/api/v1/meta/versions` (authenticated; returns `current`, `floor`, `gatedVersions`, and the pin of YOUR key) and default to its `current`. Without the header, requests use the key's stored pin (editable by the key owner in the dashboard). The SDKs send the header automatically (`LOCKED_API_VERSION`). **Never silently change a key's stored pin** — pinning is the integration owner's deliberate decision. Changelog: https://nevermined.ai/docs/development-guide/api-changelog\n\n## A1 · Get a Nevermined API key  *(needs a human once)*\n\nYou cannot mint your first key yourself — a human signs in once. **Default flow: drive a one-time browser login and capture the key automatically (Option A).** Host a `127.0.0.1` callback, **print a single sign-in URL for the human to open**, and read the key off the redirect. Do **not** ask the human to copy/paste a key or write it to a file unless Option A is genuinely impossible (no localhost callback) — then use Option B.\n\n**Option A — embedded login (the default; the key returns to you automatically).** Host a tiny callback server on `127.0.0.1` (the login page only redirects to `localhost`/`127.0.0.1` callbacks), then **print this URL and ask your human to open it**:\n\n```\nhttps://nevermined.app/auth/cli?callback_url=http://127.0.0.1:<port>/callback\n```\n\nAfter they sign in, the browser is redirected to `http://127.0.0.1:<port>/callback?nvm_api_key=<api-key>` — read `nvm_api_key` off that request. (Keys for `sandbox` start with `sandbox`; for `live`, `live`.)\n\n**Option B — manual paste (works anywhere).** Ask your human to open [nevermined.app](https://nevermined.app), sign in, create an API Key (Settings → Global NVM API Keys → **+ New API Key**), and paste it back. Or, once signed in, open `https://nevermined.app/auth/cli` with no `callback_url` to see the key on screen.\n\n**Store the key and reuse it.** Never fabricate a key; the placeholder is `sandbox:your-api-key`. Full docs: https://nevermined.ai/docs/agents-guide/get-api-key\n\n## A2 · Check your payment methods\n\n```bash\ncurl -H \"Authorization: Bearer $NVM_API_KEY\" \\\n  https://api.sandbox.nevermined.app/api/v1/payment-methods\n# → [ { id, type, brand, last4, provider, status, ... } ]\n```\n\n- A **stablecoin** payment method (an account-abstraction smart account) exists by default — **fund it** and you can pay immediately, **no human needed**. In `sandbox` it spends test USDC on Base Sepolia; see [stablecoin payments](https://nevermined.ai/docs/integrate/patterns/stablecoin-payments) for funding. Its `id` is your wallet/holder address (used in **A5**).\n- A **card** method appears here only after the one-time enrollment in **A3** below.\n- **Field shapes:** `status` is **capitalized** (`\"Active\"`, `\"Revoked\"`) and the `erc4337` method's `type` is `\"crypto_wallet\"`. (In A5, delegation cents fields like `spendingLimitCents` come back as **strings**, not numbers.)\n\nSDK: `payments.delegation.listPaymentMethods()` / `payments.delegation.list_payment_methods()`.\n\n## A3 · Enroll a card + create a delegation  *(needs a human once)*\n\nSkip this entirely if you pay with stablecoins. To pay with a card, use the **embedded browser flow** — same shape as the API key in A1: host a `127.0.0.1` callback, **print the card-setup URL for the human to open in a browser**, they sign in and enter the card, and you capture `paymentMethodId` + `delegationId` from the redirect. Open to any agent with an API key (no organization required).\n\n```bash\n# 1. Mint an embedded session (host a 127.0.0.1 callback first)\ncurl -X POST -H \"Authorization: Bearer $NVM_API_KEY\" -H \"Content-Type: application/json\" \\\n  -d '{\"returnUrl\":\"http://127.0.0.1:<port>/callback\"}' \\\n  https://api.sandbox.nevermined.app/api/v1/embed/session\n# → { \"sessionToken\": \"...\", \"userId\": \"...\", \"userWallet\": \"0x...\", \"expiresAt\": \"...\" }\n```\n\n> `POST /api/v1/embed/session` is **served but not listed in `docs-json`** (see A0) — call it directly; don't search the OpenAPI for it. It accepts any valid API key, takes only `{ returnUrl }` (a `localhost`/`127.0.0.1` URL), and returns a `sessionToken`.\n\n2. **Print the card-setup URL and ask your human to open it** in their browser:\n\n```\nhttps://embed.nevermined.app/cards/setup?sessionToken=<sessionToken>&returnUrl=http://127.0.0.1:<port>/callback&state=<random>&provider=stripe\n```\n\n3. When they finish, the browser redirects to your `returnUrl` with **`paymentMethodId`** and **`delegationId`** as query params. **Store the `delegationId`** — a delegation authorizes you to spend within a fixed budget and time window, and you reuse it until it is spent or expires. To enforce a **specific** spending cap and duration (e.g. $50 over 30 days), create the delegation explicitly with `POST /delegation/create` (below), passing the callback's `paymentMethodId` as the `providerPaymentMethodId` field.\n\n> Generate `state` as an unguessable random value and **reject the callback unless the returned `state` matches** the one you sent — it binds the response to your request (CSRF guard). And per A0, don't log the callback request line: `paymentMethodId`/`delegationId` ride in the query string.\n\n**Create a delegation explicitly.** `provider` is one of `stripe`, `braintree`, `visa` (card) or `erc4337` (stablecoin). `provider`, `currency`, `spendingLimitCents`, and `durationSecs` are **required** (no silent default for `provider` or `currency`; use `currency: \"usdc\"` for `erc4337`, `\"usd\"` for card providers).\n\n```bash\n# Stablecoin (crypto) — no card, no human. Uses your default smart-account method.\ncurl -X POST -H \"Authorization: Bearer $NVM_API_KEY\" -H \"Content-Type: application/json\" \\\n  -d '{\"provider\":\"erc4337\",\"spendingLimitCents\":10000,\"durationSecs\":604800,\"currency\":\"usdc\"}' \\\n  https://api.sandbox.nevermined.app/api/v1/delegation/create\n\n# Card (Stripe). providerPaymentMethodId is the `id` returned by GET /payment-methods.\ncurl -X POST -H \"Authorization: Bearer $NVM_API_KEY\" -H \"Content-Type: application/json\" \\\n  -d '{\"provider\":\"stripe\",\"providerPaymentMethodId\":\"pm_...\",\"spendingLimitCents\":10000,\"durationSecs\":604800,\"currency\":\"usd\"}' \\\n  https://api.sandbox.nevermined.app/api/v1/delegation/create\n# → { \"delegationId\": \"...\", \"delegationToken\": \"...\" }\n```\n\nSDK: `payments.delegation.createDelegation({ provider: 'erc4337', spendingLimitCents, durationSecs, currency: 'usdc' })`. `provider` and `currency` are **required** (no silent default); the delegation is plan-agnostic unless you pass `planId`.\n\n> **Visa caveat.** `delegation/create` *does* accept `provider: \"visa\"`, but only together with a browser-produced `consumerPrompt` + `assuranceData` from a Visa WebAuthn ceremony; omitting them is rejected with `BCK.VISA.0014` (\"requires consumerPrompt and assuranceData\"). An autonomous agent can't generate `assuranceData`, so in practice have your human create the Visa delegation in the webapp and reuse its `delegationId`.\n\n**Full detail:** the complete embedded card-enrollment handshake (session → card-setup redirect → `delegationId`), the localhost-callback rules, and every `delegation/create` field and response are in `references/autonomous-operations.md` §3.\n\n## A4 · Buy access via x402  *(fully programmatic)*\n\nTwo calls: get an access token, then settle. **x402 is the default buy flow for both rails — crypto and card work the same way, only `scheme`/`network` differ.** The facilitator charges the right method (on-chain against your delegation for crypto, the card for fiat), mints, and burns.\n\n```bash\n# 1. Get an access token (authorizes the spend against your delegation)\ncurl -X POST -H \"Authorization: Bearer $NVM_API_KEY\" -H \"Content-Type: application/json\" \\\n  -d '{\n        \"accepted\": { \"scheme\": \"nvm:erc4337\", \"network\": \"eip155:84532\", \"planId\": \"<PLAN_ID>\" },\n        \"delegationConfig\": { \"delegationId\": \"<YOUR_DELEGATION_ID>\" }\n      }' \\\n  https://api.sandbox.nevermined.app/api/v1/x402/permissions\n# → { \"accessToken\": \"...\" }\n\n# 2. Settle — charges the method, mints, and burns; this receipt is your proof of purchase\ncurl -X POST -H \"Authorization: Bearer $NVM_API_KEY\" -H \"Content-Type: application/json\" \\\n  -d '{\n        \"paymentRequired\": {\n          \"x402Version\": 2,\n          \"resource\": { \"url\": \"<PLAN_OR_RESOURCE_URL>\" },\n          \"accepts\": [ { \"scheme\": \"nvm:erc4337\", \"network\": \"eip155:84532\", \"planId\": \"<PLAN_ID>\", \"extra\": {} } ],\n          \"extensions\": {}\n        },\n        \"x402AccessToken\": \"<accessToken>\"\n      }' \\\n  https://api.sandbox.nevermined.app/api/v1/x402/settle\n# → { \"success\": true, \"billingModel\": \"credits\", \"creditsRedeemed\": \"1\", \"remainingBalance\": \"999\", \"transaction\": \"0x...\", \"network\": \"eip155:84532\" }\n```\n\n- **Pay with a card instead:** set `\"scheme\": \"nvm:card-delegation\"` and `\"network\": \"stripe\"` (or `braintree`/`visa`) in both `accepted` and `accepts[0]`.\n- **`resource.url` for a plan top-up** = the plan's own URL, `{API_BASE}/api/v1/protocol/plans/<PLAN_ID>`.\n- **Which scheme does a plan use?** `GET {API_BASE}/api/v1/protocol/plans/<PLAN_ID>` (public) returns the plan's metadata and pricing so you can pick `nvm:erc4337` vs `nvm:card-delegation` before paying. When buying from a protected agent, its `402` tells you instead.\n- **Note the field rename:** `/permissions` returns `accessToken`; pass that value as `x402AccessToken` in `/settle` and `/verify`.\n- **Dry run first (optional):** `POST /api/v1/x402/verify` with the same `{ paymentRequired, x402AccessToken }` body → `{ \"isValid\": true }`.\n- **Proof of purchase depends on `billingModel`** — read it first, it is always in the response.\n  - `\"credits\"`: `success: true` **and** `creditsRedeemed > 0` (and, for crypto, an on-chain `transaction`).\n  - `\"pay-as-you-go\"`: `success: true` **and** a non-empty `orderTx` (fiat rails) or `transaction` (crypto rails). These plans hold no credit balance, so `creditsRedeemed` and `remainingBalance` are **always the string `\"0\"` even on a charge that succeeded** — `creditsRedeemed > 0` there reports a real charge as a decline, and on a card rail that invites a retry of a payment that already went through.\n  - Both fields are **strings**: `\"0\"` is truthy while `Number(\"0\") > 0` is false, so two plausible checks disagree.\n  - **No `billingModel` at all?** The deployment predates the discriminator — apply the `credits` rule, never pay-as-you-go.\n- **Card budget caveat:** a card settle may not immediately move the delegation's `amountSpentCents`/`remainingBudgetCents` — use the settle receipt + the A5 plan balance as the source of truth for card spend, not the delegation budget.\n\n**Calling a protected agent directly** (the common case): just send the access token as the `payment-signature` header to the agent's endpoint — the agent's own `402` response **is** your `paymentRequired`, and the agent verifies + settles for you. You only call `/settle` yourself when topping up a plan with no protected endpoint to hit.\n\n> A dedicated `orderPlan` / `POST /protocol/plans/{id}/order` endpoint exists for an explicit, upfront stablecoin purchase, but **x402 above is the default for both rails — use `/order` only when specifically requested.**\n\nSDK shortcut for step 1:\n```typescript\nconst { accessToken } = await payments.x402.getX402AccessToken(planId, agentId, {\n  delegationConfig: { delegationId }        // create the delegation first via createDelegation, then pass its delegationId\n})\n```\n```python\nres = payments.x402.get_x402_access_token(plan_id, agent_id,\n    token_options=X402TokenOptions(delegation_config=DelegationConfig(delegation_id=delegation_id)))\n```\n\nFull crypto + card walkthroughs with every field: `references/autonomous-operations.md`. Subscriber-side SDK patterns: `references/client-integration.md`.\n\n## A5 · Check your purchases & credits (as a buyer)  *(fully programmatic)*\n\nYou query a plan you hold by its `<PLAN_ID>`. There is no \"list every plan I've purchased\" endpoint, so **retain the plan IDs you buy** — each `/x402/settle` receipt identifies the plan, and the plan URL embeds the id. (`GET /protocol/plans` lists plans **you published as a seller**, not ones you bought.)\n\n```bash\n# Credits left on a plan you hold. YOUR_ADDRESS = your wallet: the `id`/address of your\n# erc4337 payment method from GET /payment-methods (crypto), or the `userWallet` from POST /embed/session.\ncurl -H \"Authorization: Bearer $NVM_API_KEY\" \\\n  https://api.sandbox.nevermined.app/api/v1/protocol/plans/<PLAN_ID>/balance/<YOUR_ADDRESS>\n# → { planId, planName, planType, isSubscriber, balance, pricePerCredit, ... }\n\n# Your delegations and remaining budget\ncurl -H \"Authorization: Bearer $NVM_API_KEY\" \\\n  https://api.sandbox.nevermined.app/api/v1/delegation\n# → { totalResults, delegations: [ { delegationId, status, spendingLimitCents, amountSpentCents, remainingBudgetCents, expiresAt } ] }\n# `status` is \"Active\" | \"Expired\" | \"Exhausted\" — flag a delegation when status != \"Active\", or remainingBudgetCents is at/near 0, or expiresAt is near.\n# Caveat: a CARD delegation's budget may not reflect a card settle immediately (amountSpentCents can stay 0) — for cards, treat the settle receipt + plan balance as the spend source of truth, not the delegation budget.\n\n# A delegation's individual charges\ncurl -H \"Authorization: Bearer $NVM_API_KEY\" \\\n  https://api.sandbox.nevermined.app/api/v1/delegation/<DELEGATION_ID>/transactions\n```\n\nSDK: `payments.plans.getPlanBalance(planId)` (`PlanBalance.balance` is a `bigint` in TS / `int` in Python). The `creditsRedeemed`/`remainingBalance` you get back from `/settle` (or the decoded `payment-response` header) is also a live proof of your balance after a purchase — **on a `credits` plan**. On a `pay-as-you-go` plan both read `\"0\"` regardless of what was charged; there is no balance to prove.\n\n## A6 · Register a plan + agent (as a seller)  *(fully programmatic — SDK-first)*\n\nRegistration is the one flow where the **SDK is the recommended path**: the price/credits configs are low-level on-chain structures (amounts, receivers, token addresses, redemption type, nonce) that the SDK helpers build for you.\n\n```typescript\nconst { agentId, planId } = await payments.agents.registerAgentAndPlan(\n  { name: 'Weather Agent', description: 'Forecasts on demand', tags: ['weather'], dateCreated: new Date() },\n  { endpoints: [{ POST: 'https://your-api.com/query' }] },   // optional; omit for an open agent\n  { name: 'Starter Plan', description: '100 requests for $10', dateCreated: new Date() },\n  payments.plans.getFiatPriceConfig(10_000_000n, BUILDER_ADDRESS, 'USD'),  // $10.00 — fiat is 6-decimal units, NOT cents. Or getERC20PriceConfig(...) for crypto\n  payments.plans.getFixedCreditsConfig(100n, 1n)\n)\n```\n\nPrice helpers: `getERC20PriceConfig`/`getEURCPriceConfig` (crypto), `getFiatPriceConfig` (card). Credits helpers: `getFixedCreditsConfig` (prepaid), `getExpirableDurationConfig` (time-based), `getPayAsYouGoCreditsConfig` (per-call). The raw REST endpoints exist (`POST /api/v1/protocol/plans`, `/api/v1/protocol/agents`, `/api/v1/protocol/agents/plans`) but expect the fully-formed `priceConfig`/`creditsConfig` objects — use the SDK helpers to produce them. Full plan-type matrix and helper reference: `references/payment-plans.md`.\n\n## A7 · Check your agents' status & revenue (as a seller)  *(fully programmatic)*\n\n**Organization analytics** (require an active **Premium** org tier). **Discover your `orgId` from your own records** — every item in `GET /protocol/plans` and `/protocol/agents` carries `.orgId` + `.organizationName`; take the most common non-null `.orgId` across your published items (it's the `org-...` id, also in your `…/organizations/<orgId>/agentic-instructions.md`). Only call analytics with an id matching `^org-[0-9a-f-]+$`. Failure modes to handle (fall back to the any-tier building blocks below on any of them):\n- a **foreign / non-admin** org → `403 BCK.AUTH.0004` (\"Organisation admin privileges required\");\n- a **non-Premium** org → `403 BCK.ORGANIZATIONS.0022`;\n- a **malformed / placeholder** org id → a **silent `200` of all-zeros** — never report that as real revenue; if you have published plans but analytics returns zeros, treat it as a failure.\n\n```bash\nB=https://api.sandbox.nevermined.app/api/v1/organizations/<ORG_ID>/analytics\ncurl -H \"Authorization: Bearer $NVM_API_KEY\" \"$B/revenue?from=2026-03-20T00:00:00Z&to=2026-06-18T00:00:00Z\"\n# → { items: [ { agentId, agentName, totalRevenue, transactionCount } ], totalRevenue }\ncurl -H \"Authorization: Bearer $NVM_API_KEY\" \"$B/mrr\"\n# → { mrr, activeSubscriptions }\ncurl -H \"Authorization: Bearer $NVM_API_KEY\" \"$B/usage?from=...&to=...\"\n# → { items: [ { planId, planName, creditsBurned, uniqueUsers } ] }\ncurl -H \"Authorization: Bearer $NVM_API_KEY\" \"$B/customers?limit=20\"\n# → { items: [ { customerId, userId, totalSpent, firstSeenAt, lastActiveAt } ], totalCustomers }\n```\n\n> **Reading the analytics rows:** they're labelled `agentId`/`agentName` but are grouped **by plan**; `totalRevenue`/`totalSpent` are stringified integers in 6-decimal token units (divide by 1,000,000 for USD), while `creditsBurned` is a plain count. `mrr` is legitimately `0` when sales were one-off credit purchases rather than recurring subscriptions.\n\n**Any-tier building blocks** (no Premium required) — list what you've published and inspect each:\n\n```bash\ncurl -H \"Authorization: Bearer $NVM_API_KEY\" https://api.sandbox.nevermined.app/api/v1/protocol/plans     # your plans\ncurl -H \"Authorization: Bearer $NVM_API_KEY\" https://api.sandbox.nevermined.app/api/v1/protocol/agents    # your agents\ncurl -H \"Authorization: Bearer $NVM_API_KEY\" https://api.sandbox.nevermined.app/api/v1/protocol/agents/<AGENT_ID>/plans  # plans on an agent\n```\n\nThese return `{ total, page, offset, plans|agents: [ … ] }`, but each **item is the full record**, not a flat summary: read the name from `metadata.main.name` and price/type from `registry` / `metadata` (the `id` is the plan/agent id). The flat `{ planName, planType, pricePerCredit }` shape is only returned by the **balance** endpoint in A5, not by these list endpoints.\n\nFor per-request usage and cost observability (Helicone), see `references/seller-operations.md`, which details every seller query and the response shapes.\n\n## A8 · Onboard your own customers (white-label)  *(org admin — fully programmatic)*\n\nIf you operate an **organization**, provision Nevermined accounts for *your* customers from your backend — no member seat, recorded in your Customers CRM, and returning a **scoped key** you use to pay for your agents on their behalf. One endpoint, distinguished by `as: 'customer'`:\n\n```bash\ncurl -s -XPOST -H \"Authorization: Bearer $ORG_ADMIN_API_KEY\" -H \"Content-Type: application/json\" \\\n  -d '{\"email\":\"customer@example.com\",\"as\":\"customer\"}' \\\n  https://api.sandbox.nevermined.app/api/v1/organizations/account\n# New / returning customer → 201, walletResult.nvmApiKey (+ userId, userWallet, isCustomer, customerRecorded) — the USABLE key\n# Email owned by a non-customer account → 202, walletResult.consentRequired=true (consent email sent; no key or identity disclosed)\n```\n\nSDK: `payments.organizations.onboardCustomer(email)` (TS) / `payments.organizations.onboard_customer(email)` (Python). The key is scoped to **purchase + redeem only** (not register/mint), short-lived (~30d), and revocable — use it to buy access (A4) and check credits (A5) on the customer's behalf. Full flow, the three provenance outcomes, and SDK code: `references/customer-onboarding.md`.\n\n## A9 · Receive payments in your own agent\n\nIf your goal is to make **your** agent charge its callers (not to buy from others), that is **Track B** below — it shows how to gate Express/FastAPI/MCP/A2A/Strands endpoints behind a plan with `verifyPermissions` / `settlePermissions` or framework middleware.\n\n---\n\n# Track B — Add payments to your code\n\nUse this track to wire Nevermined into an agent or API **so it can receive payments**. This is SDK-first (TypeScript / Python).\n\n## Prerequisite: a Nevermined API Key\n\nAll SDK, REST, and CLI calls require an `NVM_API_KEY` (see **A1** for how to obtain one). Set it as an environment variable:\n\n```bash\nexport NVM_API_KEY=\"sandbox:your-api-key\"\n```\n\nIf the developer has no `NVM_API_KEY` yet, point them to **A1** before generating code that needs it. Use `sandbox:your-api-key` as the placeholder in generated code — a realistic-looking fake key gets mistaken for a real one.\n\n## Environment Setup\n\n| Variable | Required | Description |\n|---|---|---|\n| `NVM_API_KEY` | Yes | Your Nevermined API key — see [Get Your API Key](https://nevermined.ai/docs/agents-guide/get-api-key) |\n| `NVM_ENVIRONMENT` | Yes | `sandbox` for testing, `live` for production |\n| `NVM_PLAN_ID` | Yes | The plan ID from registration |\n| `NVM_AGENT_ID` | Sometimes | Required for plans with multiple agents; optional (informational) for MCP servers |\n| `BUILDER_ADDRESS` | For registration | Wallet address to receive payments |\n\n### `.env` Template\n\n```bash\n# Required\nNVM_API_KEY=sandbox:your-api-key\nNVM_ENVIRONMENT=sandbox\nNVM_PLAN_ID=your-plan-id-here\n\n# Required for multi-agent plans (optional for MCP servers)\nNVM_AGENT_ID=your-agent-id-here\n\n# Required for registration\nBUILDER_ADDRESS=0xYourWalletAddress\n```\n\n### Prerequisites\n\n- **TypeScript/Express.js**: Node.js 20+. Your `package.json` must include `\"type\": \"module\"` for the `@nevermined-io/payments/express` subpath import to work.\n- **Python/FastAPI**: Python 3.10+. Install with `pip install payments-py[fastapi]` — the `[fastapi]` extra is required for the middleware.\n\n### TypeScript\n\n```bash\nnpm install @nevermined-io/payments\n```\n\n```typescript\nimport { Payments } from '@nevermined-io/payments'\n\nconst payments = Payments.getInstance({\n  nvmApiKey: process.env.NVM_API_KEY!,\n  environment: 'sandbox'\n})\n```\n\n### Python\n\n```bash\npip install payments-py\n```\n\n```python\nimport os\nfrom payments_py import Payments, PaymentOptions\n\npayments = Payments.get_instance(\n    PaymentOptions(\n        nvm_api_key=os.environ[\"NVM_API_KEY\"],\n        environment=\"sandbox\"\n    )\n)\n```\n\n## Core Workflow (All Integrations)\n\nEvery Nevermined payment integration follows this 5-step pattern:\n\n1. **Client sends request** without a payment token\n2. **Server returns 402** with `payment-required` header (base64-encoded JSON with plan info)\n3. **Client acquires x402 token** via `payments.x402.getX402AccessToken(planId, agentId, { delegationConfig: { delegationId } })` — create the delegation first with `createDelegation` (`provider` + `currency` required), then pass its `delegationId` (inline create-on-the-fly is deprecated)\n4. **Client retries** with `payment-signature` header containing the token\n5. **Server verifies → executes → settles** (burns credits), returns response with `payment-response` header\n\n## Framework Decision Tree\n\nChoose the integration that matches your stack:\n\n| Framework | Language | Reference | Key Import |\n|---|---|---|---|\n| **Express.js** | TypeScript/JS | `references/express-integration.md` | `paymentMiddleware` from `@nevermined-io/payments/express` |\n| **FastAPI** | Python | `references/fastapi-integration.md` | `PaymentMiddleware` from `payments_py.x402.fastapi` |\n| **Strands Agent** | Python | `references/strands-integration.md` | `@requires_payment` from `payments_py.x402.strands` |\n| **LangChain / LangGraph** | TS / Python | `references/langchain-integration.md` | `@requires_payment` from `payments_py.x402.langchain` / `requiresPayment` from `@nevermined-io/payments/langchain` |\n| **MCP Server** | TS / Python | `references/mcp-paywall.md` (TypeScript examples; Python has `payments.mcp.register_tool()` / `start()`) | `payments.mcp.start()` / `payments.mcp.registerTool()` |\n| **Google A2A** | TS / Python | `references/a2a-integration.md` | `payments.a2a.start()` / `Payments.a2a.buildPaymentAgentCard()` (static) |\n| **Any HTTP** | Any | `references/x402-protocol.md` | Manual verify/settle via facilitator API |\n| **Client-side** | TS / Python | `references/client-integration.md` | `payments.x402.getX402AccessToken()` with `delegationConfig` |\n\n## SDK Quick Reference\n\n### TypeScript (`@nevermined-io/payments`)\n\n```typescript\n// Initialize\nconst payments = Payments.getInstance({ nvmApiKey, environment })\n\n// Build price + credits configs (pick one helper per axis)\nconst priceConfig =\n  payments.plans.getERC20PriceConfig(10_000_000n, USDC_ADDRESS, builderAddress)\n  // or getEURCPriceConfig / getNativeTokenPriceConfig / getFreePriceConfig\n  // or getFiatPriceConfig(amount, builderAddress, 'USD') for Stripe/Braintree\n  // or await getPayAsYouGoPriceConfig(amount, builderAddress, tokenAddress?)\n\nconst creditsConfig =\n  payments.plans.getFixedCreditsConfig(100n, 1n)\n  // or getDynamicCreditsConfig / getExpirableDurationConfig\n  // or getPayAsYouGoCreditsConfig() for PAYG plans\n\n// Register agent + plan\nconst { agentId, planId } = await payments.agents.registerAgentAndPlan(\n  agentMetadata, agentApi, planMetadata, priceConfig, creditsConfig\n)\n\n// Subscriber: order plan and get token\nawait payments.plans.orderPlan(planId)\nconst planBalance = await payments.plans.getPlanBalance(planId)\nconsole.log(`Credits remaining: ${planBalance.balance}`)  // PlanBalance.balance is bigint\n\n// Create the delegation first (provider + currency required), then request the token by delegationId.\nconst delegation = await payments.delegation.createDelegation({\n  provider: 'erc4337', spendingLimitCents: 100, durationSecs: 3600, currency: 'usdc'\n})\nconst { accessToken } = await payments.x402.getX402AccessToken(planId, agentId, {\n  delegationConfig: { delegationId: delegation.delegationId }\n})\n\n// Server: verify and settle\nconst verification = await payments.facilitator.verifyPermissions({\n  paymentRequired, x402AccessToken: token, maxAmount: BigInt(credits)\n})\nconst settlement = await payments.facilitator.settlePermissions({\n  paymentRequired, x402AccessToken: token, maxAmount: BigInt(creditsUsed)\n})\n\n// Helpers\nimport { buildPaymentRequired } from '@nevermined-io/payments'\nimport { paymentMiddleware, X402_HEADERS } from '@nevermined-io/payments/express'\n\n// MCP server\npayments.mcp.registerTool(name, config, handler, { credits: 5n })\nconst { info, stop } = await payments.mcp.start({ port, planId, serverName })  // planId required; agentId optional\n\n// A2A server\nconst agentCard = Payments.a2a.buildPaymentAgentCard(baseCard, { paymentType, credits, planId, agentId })  // static, on the class\nconst server = await payments.a2a.start({ port, basePath: '/a2a/', agentCard, executor })\n// A2A client\nconst client = await payments.a2a.getClient({ agentBaseUrl, agentId, planId, delegationConfig: { delegationId } })\n// sendA2AMessage mints the x402 token from delegationConfig and carries it in band\nawait client.sendA2AMessage({ message: { kind: 'message', role: 'user', messageId: crypto.randomUUID(), parts: [{ kind: 'text', text: 'Hello' }] } })\n```\n\n### Python (`payments-py`)\n\n```python\nimport asyncio\nfrom payments_py.x402 import CreateDelegationPayload, DelegationConfig, X402TokenOptions\n\n# Initialize\npayments = Payments.get_instance(PaymentOptions(nvm_api_key=key, environment=\"sandbox\"))\n\n# Build price + credits configs (helpers exist on payments.plans and as module funcs)\nprice_config = payments.plans.get_erc20_price_config(10_000_000, USDC_ADDRESS, builder_address)\n# or get_eurc_price_config / get_native_token_price_config / get_free_price_config\n# or get_fiat_price_config(amount, builder_address, \"USD\") for Stripe/Braintree\n# or payments.plans.get_pay_as_you_go_price_config(...)  (sync; uses cached contract address)\ncredits_config = payments.plans.get_fixed_credits_config(100, 1)\n\n# Register agent + plan\nresult = payments.agents.register_agent_and_plan(\n    agent_metadata, agent_api, plan_metadata, price_config, credits_config\n)\n\n# Subscriber: order plan and get token\npayments.plans.order_plan(plan_id)\nplan_balance = payments.plans.get_plan_balance(plan_id)\nprint(f\"Credits remaining: {plan_balance.balance}\")  # PlanBalance.balance is int\n# Create the delegation first (provider + currency required), then request the token by delegation_id.\ndelegation = payments.delegation.create_delegation(\n    CreateDelegationPayload(\n        provider=\"erc4337\", spending_limit_cents=100, duration_secs=3600, currency=\"usdc\"\n    )\n)\ntoken_res = payments.x402.get_x402_access_token(\n    plan_id, agent_id,\n    token_options=X402TokenOptions(\n        delegation_config=DelegationConfig(delegation_id=delegation.delegation_id)\n    )\n)\n\n# Server: verify and settle\nverification = payments.facilitator.verify_permissions(\n    payment_required=pr, x402_access_token=token, max_amount=str(credits)\n)\nsettlement = payments.facilitator.settle_permissions(\n    payment_required=pr, x402_access_token=token, max_amount=str(credits_used)\n)\n\n# Helpers\nfrom payments_py.x402.helpers import build_payment_required\nfrom payments_py.x402.fastapi import PaymentMiddleware\nfrom payments_py.x402.strands import requires_payment\n\n# A2A server\nfrom payments_py.a2a.agent_card import build_payment_agent_card\nfrom payments_py.a2a.server import PaymentsA2AServer\nagent_card = build_payment_agent_card(base_card, { ... })\nserver = PaymentsA2AServer.start(agent_card=agent_card, executor=executor, payments_service=payments, port=3005)\n# A2A client\n# payments.a2a is a dict of helpers; the client mints the token from delegation_config\nclient = payments.a2a[\"get_client\"](\n    agent_base_url=url, agent_id=agent_id, plan_id=plan_id,\n    delegation_config=DelegationConfig(delegation_id=delegation_id),\n)\nresult = asyncio.run(client.send_message({\"message\": {\"kind\": \"message\", \"role\": \"user\", \"messageId\": \"1\", \"parts\": [{\"kind\": \"text\", \"text\": \"Hello\"}]}}))  # or `await` inside async code\n```\n\n## x402 Payment Headers\n\nHTTP integrations (Express, FastAPI, generic HTTP) use these three headers. MCP and A2A carry the same payloads in band instead — MCP in the request/result `_meta` (`x402/payment`, `x402/payment-response`), A2A in the message metadata — see their reference files.\n\n| Header | Direction | Description |\n|---|---|---|\n| `payment-signature` | Client → Server | x402 access token |\n| `payment-required` | Server → Client (402) | Base64-encoded JSON with plan requirements |\n| `payment-response` | Server → Client (200) | Base64-encoded JSON settlement receipt |\n\nThe `payment-required` payload structure:\n```json\n{\n  \"x402Version\": 2,\n  \"resource\": { \"url\": \"/api/endpoint\" },\n  \"accepts\": [{\n    \"scheme\": \"nvm:erc4337\",\n    \"network\": \"eip155:84532\",\n    \"planId\": \"<plan-id>\",\n    \"extra\": { \"agentId\": \"<agent-id>\" }\n  }],\n  \"extensions\": {}\n}\n```\n\n### Supported x402 schemes\n\n| Scheme | Network field | Settlement |\n|---|---|---|\n| `nvm:erc4337` | CAIP-2 chain ID (e.g. `eip155:84532` Base Sepolia, `eip155:8453` Base Mainnet) | Crypto stablecoins (USDC / EURC) via account-abstraction delegation |\n| `nvm:card-delegation` | Fiat provider (`stripe`, `braintree`, or `visa`) | Card-on-file via Stripe / Braintree / Visa Agentic Token delegation |\n\nThe SDK auto-resolves the scheme from the plan's `priceConfig` metadata. You only need to pass `scheme` explicitly if you want to override it.\n\n## Payment Plan Types\n\nNevermined supports several plan types:\n\n- **Credits-based**: prepaid balance, deducted per request (most common for APIs). Use `getFixedCreditsConfig` or `getDynamicCreditsConfig`.\n- **Time-based**: access for a fixed duration (e.g., 30 days unlimited). Use `getExpirableDurationConfig`.\n- **Pay-as-you-go (PAYG)**: one credit granted and burned per purchase — clients re-purchase before each call. Use `getPayAsYouGoPriceConfig` + `getPayAsYouGoCreditsConfig`.\n- **Trial**: free limited access, one-time claim per user. Use `getFreePriceConfig`.\n- **Hybrid**: combine fixed credits with a time expiry by passing `accessLimit: 'time'` and an expirable duration config.\n\nEach plan can be priced in **crypto** (`getERC20PriceConfig`, `getEURCPriceConfig`, `getNativeTokenPriceConfig`) or **fiat** (`getFiatPriceConfig` — Stripe / Braintree / Visa Trusted Agent). The selected price helper determines the x402 scheme used at runtime.\n\nFor fiat plans, the active provider is selected per plan via the `fiatPaymentProvider` metadata field (`'stripe'`, `'braintree'`, or `'visa'`). Sellers using Braintree must connect a Braintree merchant account with at least one child merchant account in the plan's currency. Sellers offering Visa Trusted Agent plans must complete Stripe Connect onboarding (Visa delegations settle through Stripe Connect) — see [Braintree onboarding](https://nevermined.ai/docs/products/payments/braintree-onboarding) for the Braintree seller setup and [card enrollment](https://nevermined.ai/docs/products/payments/card-enrollment) for the buyer-side flow.\n\n**Visa caveat for SDK builders.** Visa delegation creation is browser-only — it requires `consumerPrompt` + `assuranceData` produced by an in-browser WebAuthn ceremony embedded by Visa VTS. The SDK can **consume** an existing Visa delegation by passing its `delegationId` to `DelegationConfig`, but calling `createDelegation` / `create_delegation` with `provider: 'visa'` is rejected by the backend (`BCK.VISA.0014`). For any SDK code path that needs a Visa delegation, instruct the user to create it in the Nevermined webapp and pass the resulting ID back to the agent.\n\nSee `references/payment-plans.md` for plan registration code.\n\n## Common Patterns\n\nPer-framework snippets — fixed and dynamic credits per route, paywalled MCP tools, the Strands decorator, A2A server and client — live in each framework's reference file (see the **Framework Decision Tree** above).\n\n## Gathering Developer Information Upfront\n\nAn integration needs the following. Read the project first (framework, routes, `.env`) and ask the developer, in one message, only for what you can't determine there:\n\n1. **Framework**: Express.js, FastAPI, MCP server, Strands agent, LangChain / LangGraph, Google A2A, or generic HTTP\n2. **Routes to protect** and the credits each costs (e.g. `POST /chat = 1 credit, POST /generate = 5 credits`)\n3. **Pricing model**: fixed credits per request, or dynamic based on request/response parameters\n4. **Nevermined API key**: whether `NVM_API_KEY` exists; if not, direct them to **A1**\n5. **Plan ID**: whether `NVM_PLAN_ID` exists; if not, whether they also want a registration script\n6. **Environment**: `sandbox` (testing) or `live` (production)\n\nFor plan registration, also: plan name and description, price (e.g. 10 USDC for 100 credits), credits per plan, and the builder wallet address (`BUILDER_ADDRESS`) that receives payments.\n\n## Agent and Plan Registration\n\n**SDK (recommended):** `registerAgentAndPlan` / `register_agent_and_plan` as shown in **A6**; full TypeScript and Python code in `references/payment-plans.md`.\n\n**No-code:** sign in at [nevermined.app](https://nevermined.app) → **My agents**, register the agent, create and link a plan, publish, and copy the `agentId` and `planId` into your `.env`.\n\n### Using the CLI\n\n```bash\n# 1. Install CLI\nnpm install -g @nevermined-io/cli\n\n# 2. Configure (use sandbox for testing)\nnevermined config init --api-key \"$NVM_API_KEY\" --environment sandbox\n\n# 3. Build the helper-shaped configs and register\n#    The --price-config / --credits-config flags expect the JSON shape\n#    produced by Plans.getERC20PriceConfig and Plans.getFixedCreditsConfig —\n#    the helper subcommands below emit exactly that shape with --format json.\nPRICE=$(nevermined plans get-erc20-price-config \\\n  --amount 10000000 \\\n  --token-address 0x036CbD53842c5426634e7929541eC2318f3dCF7e \\\n  --receiver $BUILDER_ADDRESS \\\n  --format json)\nCREDITS=$(nevermined plans get-fixed-credits-config \\\n  --credits-granted 100 \\\n  --credits-per-request 1 \\\n  --format json)\n\nnevermined agents register-agent-and-plan \\\n  --agent-metadata '{\"name\":\"My Agent\",\"description\":\"AI service\"}' \\\n  --agent-api '{\"endpoints\":[{\"POST\":\"https://your-api.com/query\"}]}' \\\n  --plan-metadata '{\"name\":\"Starter Plan\",\"description\":\"100 requests\"}' \\\n  --price-config \"$PRICE\" \\\n  --credits-config \"$CREDITS\"\n\n# 4. List your plans\nnevermined plans get-plans\n\n# 5. As a subscriber: order a plan and get an x402 token\n#    For fiat plans, pass --payment-type fiat (defaults to crypto).\nnevermined plans order-plan $PLAN_ID\nnevermined x402token get-x402-access-token $PLAN_ID \\\n  --agent-id $AGENT_ID \\\n  --spending-limit-cents 10000 \\\n  --delegation-duration-secs 604800\n\n# 6. Test against your running server\ncurl -X POST http://localhost:3000/chat \\\n  -H \"Content-Type: application/json\" \\\n  -H \"payment-signature: $TOKEN\" \\\n  -d '{\"message\": \"Hello\"}'\n```\n\n## Troubleshooting\n\n| Symptom | Cause | Fix |\n|---|---|---|\n| HTTP 402 returned | No `payment-signature` header or invalid/expired token | Generate a fresh token via `getX402AccessToken` with `delegationConfig` |\n| `401 BCK.AUTH.0002` on a REST call | Missing/expired API key | Send `Authorization: Bearer $NVM_API_KEY`; mint a key per **A1** |\n| `403` on analytics — `BCK.ORGANIZATIONS.0022` (not Premium) or `BCK.AUTH.0004` (not an admin of that org) | Wrong tier, not your org, or a malformed `orgId` (which instead returns a **silent 200-of-zeros**) | Discover the real `orgId` from `.orgId` on your plan/agent records; use the any-tier building blocks in **A7**, or upgrade the org |\n| `BCK.VISA.0014` creating a delegation | `provider:\"visa\"` sent without the browser-produced `consumerPrompt` + `assuranceData` | An agent can't produce `assuranceData` — create the Visa delegation in the webapp; reuse the `delegationId` |\n| `BCK.X402.0002` Plan not found | Wrong `planId` or wrong environment | Verify the plan ID and that you are calling the matching `sandbox`/`live` base URL |\n| MCP tool result with `isError: true` and a `PaymentRequired` object in `structuredContent` (resources/prompts: a JSON-RPC error) | Payment Required — no token, invalid token, insufficient credits, or settlement failed after the call | Check subscriber has purchased plan and has credits remaining |\n| MCP error `-32002` | Server misconfiguration | Verify `NVM_API_KEY`, `NVM_PLAN_ID`, and `NVM_AGENT_ID` are set correctly |\n| `verification.isValid` is false | Token expired/invalid, wrong plan, **plan not linked to the agent**, or insufficient credits | Regenerate the token; if it persists, verify the plan is associated with the agent and that credits remain (don't just loop on token regeneration) |\n| Credits not deducting | Settlement not called after request | Ensure you call `settlePermissions` after processing (middleware does this automatically) |\n| `payment-required` header missing | Server not returning 402 properly | Use `buildPaymentRequired()` helper or framework middleware |\n\n## Additional Resources\n\n- **Documentation**: [nevermined.ai/docs](https://nevermined.ai/docs)\n- **Autonomous agent purchase guide**: [nevermined.ai/docs/getting-started/ai-agent-purchase](https://nevermined.ai/docs/getting-started/ai-agent-purchase)\n- **Card enrollment & delegation**: [nevermined.ai/docs/solutions/card-delegation](https://nevermined.ai/docs/solutions/card-delegation)\n- **Nevermined App**: [nevermined.app](https://nevermined.app) — register agents, create plans, manage subscriptions\n- **API discovery (per environment)**: `GET {API_BASE}/api/v1/rest/docs-json` (OpenAPI JSON)\n- **MCP Search Server**: `https://nevermined.ai/docs/mcp` — search Nevermined docs from any MCP client\n- **Tutorials**: [github.com/nevermined-io/tutorials](https://github.com/nevermined-io/tutorials)\n- **Discord**: [discord.com/invite/GZju2qScKq](https://discord.com/invite/GZju2qScKq)\n- **TypeScript SDK**: `@nevermined-io/payments` on npm\n- **Python SDK**: `payments-py` on PyPI\n\nFile v1.0.10:_meta.json\n\n{\n  \"ownerId\": \"kn7bk8z6x7ytxvdb48j34j2ahh812m3p\",\n  \"slug\": \"nevermined\",\n  \"version\": \"1.0.10\",\n  \"publishedAt\": 1790357689120\n}\n\nFile v1.0.10:references/a2a-integration.md\n\n# Google A2A Integration\n\nIntegrate Nevermined payments with [Google A2A (Agent-to-Agent)](https://a2a-protocol.org/) to enable multi-agent systems to authorize and charge per request between agents.\n\n> 🔐 **Trust & transport.** A2A flows ship payment tokens (`payment-signature`) between agents — they are bearer credentials. Always: (1) serve agents over HTTPS, (2) validate the peer Agent Card and base URL before sending tokens, (3) restrict CORS to known agent origins, (4) issue short-lived, narrowly scoped **delegations** (`createDelegation` with tight `spendingLimitCents` + `durationSecs`), then request tokens by their `delegationId`, and (5) treat push-notification webhook URLs as untrusted until verified.\n\n## Features\n\n- **Agent Card with payment extension**: served at `/.well-known/agent-card.json` (legacy alias `/.well-known/agent.json`)\n- **In-band payment (x402 v2 A2A transport)**: the client carries the x402 payload in the JSON-RPC message metadata; the `payment-signature` HTTP header is still accepted as a deprecated fallback\n- **Credits Validation**: verify sufficient credits before executing a task\n- **Credits Burning/Redemption**: burn credits specified in `metadata.creditsUsed` after execution\n- **Streaming**: supports `message/stream` and `tasks/resubscribe`\n- **Push Notifications**: standard A2A push notification flow\n- **Async Task Handling**: intermediate and final state events, compatible with polling and streaming\n\n## Installation\n\n### TypeScript\n\n```bash\nnpm install @nevermined-io/payments\n```\n\n### Python\n\n```bash\npip install payments-py\n```\n\n## A2A Server\n\n### Build the Payment Agent Card\n\nAdd a Nevermined payment extension to your A2A agent card to advertise that your agent charges for requests.\n\n#### TypeScript\n\n```typescript\nimport { Payments } from \"@nevermined-io/payments\"\n\nconst payments = Payments.getInstance({\n  nvmApiKey: process.env.NVM_API_KEY!,\n  environment: 'sandbox',\n})\n\nconst baseAgentCard = {\n  name: 'My A2A Server',\n  description: 'A2A agent that requires payment',\n  capabilities: {\n    streaming: true,\n    pushNotifications: true,\n    stateTransitionHistory: true,\n  },\n  defaultInputModes: ['text'],\n  defaultOutputModes: ['text'],\n  skills: [],\n  url: 'http://localhost:3005/a2a/',\n  version: '1.0.0',\n}\n\n// buildPaymentAgentCard is static on the Payments class (not on the `payments` instance)\nconst agentCard = Payments.a2a.buildPaymentAgentCard(baseAgentCard, {\n  paymentType: \"dynamic\",\n  credits: 1,\n  planId: process.env.NVM_PLAN_ID!,\n  agentId: process.env.NVM_AGENT_ID!,\n})\n```\n\n#### Python\n\n```python\nfrom payments_py import Payments, PaymentOptions\nfrom payments_py.a2a.agent_card import build_payment_agent_card\n\npayments = Payments.get_instance(\n    PaymentOptions(nvm_api_key=os.environ[\"NVM_API_KEY\"], environment=\"sandbox\")\n)\n\nbase_agent_card = {\n    \"name\": \"My A2A Agent\",\n    \"description\": \"A2A agent that requires payment\",\n    \"capabilities\": {\n        \"streaming\": True,\n        \"pushNotifications\": True,\n        \"stateTransitionHistory\": True,\n    },\n    \"defaultInputModes\": [\"text\"],\n    \"defaultOutputModes\": [\"text\"],\n    \"skills\": [],\n    \"url\": \"https://your-agent.example.com/a2a/\",\n    \"version\": \"1.0.0\",\n}\n\nagent_card = build_payment_agent_card(base_agent_card, {\n    \"paymentType\": \"dynamic\",\n    \"credits\": 1,\n    \"costDescription\": \"Dynamic cost per request\",\n    \"planId\": os.environ[\"NVM_PLAN_ID\"],\n    \"agentId\": os.environ[\"NVM_AGENT_ID\"],\n})\n```\n\n### Payment Extension JSON\n\nThe `buildPaymentAgentCard` helper adds this extension to your agent card:\n\n```json\n{\n  \"capabilities\": {\n    \"extensions\": [\n      {\n        \"uri\": \"urn:nevermined:payment\",\n        \"description\": \"Dynamic cost per request\",\n        \"required\": false,\n        \"params\": {\n          \"paymentType\": \"dynamic\",\n          \"credits\": 1,\n          \"planId\": \"<planId>\",\n          \"agentId\": \"<agentId>\"\n        }\n      }\n    ]\n  }\n}\n```\n\nImportant: the `url` in the agent card must match the URL registered in Nevermined for the agent/plan.\n\n### Start the A2A Server\n\n#### TypeScript\n\n```typescript\nclass Executor implements AgentExecutor {\n  async handleTask(context, eventBus) {\n    // Your business logic here\n    // Returns { result: TaskHandlerResult, expectsMoreUpdates: boolean }\n  }\n  async cancelTask(taskId) { /* ... */ }\n\n  async execute(requestContext, eventBus) {\n    const { result, expectsMoreUpdates } = await this.handleTask(requestContext, eventBus)\n    if (expectsMoreUpdates) return\n    // Publish final status-update event with metadata.creditsUsed\n  }\n}\n\nconst serverResult = await payments.a2a.start({\n  port: 3005,\n  basePath: '/a2a/',\n  agentCard: agentCard,\n  executor: new Executor(),\n})\n```\n\n#### Python\n\n```python\nfrom uuid import uuid4\nfrom a2a.server.agent_execution.agent_executor import AgentExecutor\nfrom a2a.types import Message, Role, TaskState, TaskStatus, TaskStatusUpdateEvent\nfrom payments_py.a2a.server import PaymentsA2AServer\n\nclass MyExecutor(AgentExecutor):\n    async def execute(self, context, event_queue):\n        # Your business logic here\n        await event_queue.enqueue_event(\n            TaskStatusUpdateEvent(\n                task_id=context.task_id,\n                context_id=context.context_id,\n                status=TaskStatus(\n                    state=TaskState.completed,\n                    message=Message(\n                        message_id=str(uuid4()),\n                        role=Role.agent,\n                        parts=[{\"kind\": \"text\", \"text\": \"Done\"}],\n                        task_id=context.task_id,\n                        context_id=context.context_id,\n                    ),\n                ),\n                final=True,\n                metadata={\"creditsUsed\": 1},  # credits to burn\n            )\n        )\n\n    async def cancel(self, context, event_queue):\n        raise NotImplementedError\n\nserver = PaymentsA2AServer.start(\n    agent_card=agent_card,\n    executor=MyExecutor(),\n    payments_service=payments,\n    port=3005,\n    base_path=\"/a2a/\",\n)\n```\n\nThe final streaming event must include `metadata.creditsUsed` with the consumed cost. Nevermined validates and burns credits accordingly.\n\n## A2A Client\n\n### Initialize the Client\n\nThe client mints the x402 access token itself from the delegation you pass in, so create the delegation first.\n\n#### TypeScript\n\n```typescript\nconst paymentsSubscriber = Payments.getInstance({\n  nvmApiKey: process.env.NVM_API_KEY!,\n  environment: 'sandbox',\n})\n\n// Create the delegation first (provider + currency required)\nconst delegation = await paymentsSubscriber.delegation.createDelegation({\n  provider: 'erc4337', spendingLimitCents: 100, durationSecs: 3600, currency: 'usdc'\n})\n\n// getClient is async\nconst client = await paymentsSubscriber.a2a.getClient({\n  agentBaseUrl: 'http://localhost:3005/a2a/',\n  agentId: process.env.NVM_AGENT_ID!,\n  planId: process.env.NVM_PLAN_ID!,\n  delegationConfig: { delegationId: delegation.delegationId },\n})\n```\n\n#### Python\n\n```python\nfrom payments_py.x402 import CreateDelegationPayload, DelegationConfig\n\npayments_subscriber = Payments.get_instance(\n    PaymentOptions(nvm_api_key=os.environ[\"NVM_API_KEY\"], environment=\"sandbox\")\n)\n\ndelegation = payments_subscriber.delegation.create_delegation(\n    CreateDelegationPayload(\n        provider=\"erc4337\", spending_limit_cents=100, duration_secs=3600, currency=\"usdc\"\n    )\n)\n\n# payments.a2a is a dict of helpers\nclient = payments_subscriber.a2a[\"get_client\"](\n    agent_base_url=\"https://your-agent.example.com/a2a/\",\n    agent_id=os.environ[\"NVM_AGENT_ID\"],\n    plan_id=os.environ[\"NVM_PLAN_ID\"],\n    delegation_config=DelegationConfig(delegation_id=delegation.delegation_id),\n)\n```\n\n### Send a Task\n\n#### TypeScript\n\n```typescript\n// Purchase the plan\nawait paymentsSubscriber.plans.orderPlan(planId)\n\n// sendA2AMessage mints the x402 token from delegationConfig and carries it in band\nconst response = await client.sendA2AMessage({\n  message: {\n    kind: 'message',\n    role: 'user',\n    messageId: crypto.randomUUID(),\n    parts: [{ kind: 'text', text: 'Hello, analyze this data!' }],\n  },\n})\nconst taskId = response?.result?.id\n```\n\n#### Python\n\n```python\n# Send a simple request\nresult = await client.send_message({\n    \"message\": {\n        \"kind\": \"message\",\n        \"role\": \"user\",\n        \"messageId\": \"123\",\n        \"parts\": [{\"kind\": \"text\", \"text\": \"Hello\"}]\n    }\n})\n\n# Stream events\nasync for event in client.send_message_stream({\n    \"message\": {\n        \"kind\": \"message\",\n        \"role\": \"user\",\n        \"messageId\": \"124\",\n        \"parts\": [{\"kind\": \"text\", \"text\": \"Stream this\"}]\n    }\n}):\n    if event.get(\"result\", {}).get(\"final\"):\n        break\n```\n\n## Environment Variables\n\n```bash\nNVM_API_KEY=sandbox:your-api-key\nNVM_ENVIRONMENT=sandbox\nNVM_PLAN_ID=your-plan-id\nNVM_AGENT_ID=your-agent-id\n```\n\n## Tutorial\n\nComplete working example: [github.com/nevermined-io/a2a-agent-client-sample](https://github.com/nevermined-io/a2a-agent-client-sample)\n\nFile v1.0.10:references/autonomous-operations.md\n\n# Autonomous Agent Operations (REST runbook)\n\nHow an AI agent operates on Nevermined **on its own behalf** using the REST API — get an API key, enroll a card, create a delegation, purchase plans via x402, and check status. Every call here is plain HTTPS; no SDK install is required. This is the heavy-detail companion to **Track A** in `SKILL.md`.\n\n> All bodies and response shapes below are verified against the live sandbox OpenAPI (`https://api.sandbox.nevermined.app/api/v1/rest/docs-json`). Send `Authorization: Bearer $NVM_API_KEY` on every call unless noted.\n>\n> Also send `Nevermined-Version: <MAJOR.MINOR>` on every call to pin the wire shape across platform releases — discover the supported range with `GET /api/v1/meta/versions` and default to its `current`. Never silently change a key's stored pin.\n\n## Environments\n\n| Environment | API base URL | App | Card enrollment UI | Crypto network | Key prefix |\n|---|---|---|---|---|---|\n| `sandbox` | `https://api.sandbox.nevermined.app` | `https://nevermined.app` | `https://embed.nevermined.app` | `eip155:84532` (Base Sepolia) | `sandbox:` |\n| `live` | `https://api.live.nevermined.app` | `https://nevermined.app` | `https://embed.nevermined.app` | `eip155:8453` (Base Mainnet) | `live:` |\n\nOnly `sandbox` and `live` are public. Use the exact base URL — never infer it.\n\n## What needs a human (once) vs. fully programmatic\n\n| Step | Human? |\n|---|---|\n| Get the first API key | **Yes, once** (browser sign-in) |\n| Enroll a card | **Yes, once** (browser; skip entirely for stablecoins) |\n| Check payment methods, create delegation, get token, settle, register, status, revenue | No — fully programmatic |\n\n---\n\n## 1. Get a Nevermined API key\n\nYou cannot mint the first key yourself.\n\n**Option A — embedded login (key returns automatically).** Host an HTTP server on `127.0.0.1:<port>` with a `/callback` route, then have your human open:\n\n```\nhttps://nevermined.app/auth/cli?callback_url=http://127.0.0.1:<port>/callback\n```\n\nAfter sign-in the browser hits `http://127.0.0.1:<port>/callback?nvm_api_key=<api-key>`. Read `nvm_api_key`, store it, reuse it.\n\n**Option B — manual paste.** Human signs in at [nevermined.app](https://nevermined.app) → Settings → Global NVM API Keys → **+ New API Key**, and pastes it back. Or opens `https://nevermined.app/auth/cli` (no `callback_url`) to read the key on screen.\n\nA `sandbox` key starts with `sandbox`; a `live` key with `live`.\n\n---\n\n## 2. Check your payment methods\n\n```bash\ncurl -s -H \"Authorization: Bearer $NVM_API_KEY\" \\\n  https://api.sandbox.nevermined.app/api/v1/payment-methods\n```\n\nResponse — array of payment methods:\n\n```json\n[\n  {\n    \"id\": \"pm_1Q...\",\n    \"type\": \"card\",\n    \"brand\": \"visa\",\n    \"last4\": \"4242\",\n    \"expMonth\": 12,\n    \"expYear\": 2030,\n    \"alias\": \"My Card\",\n    \"provider\": \"stripe\",\n    \"status\": \"Active\",\n    \"allowedApiKeyIds\": null\n  }\n]\n```\n\nA **stablecoin** method exists by default (fund it to pay immediately). A **card** method only appears after the one-time enrollment in step 3.\n\n---\n\n## 3. Enroll a card + create a delegation\n\nOnly needed to pay with a card. Two parts: enroll the card (browser, one-time), then you have a delegation. The default flow: host a `127.0.0.1` callback, **print the card-setup URL for the human to open in a browser**, they enter the card, and you capture `paymentMethodId` + `delegationId` from the redirect.\n\n> `POST /api/v1/embed/session` is served but **not** listed in the OpenAPI (`docs-json`) — call it directly; don't search the OpenAPI for it.\n\n### 3a. Embedded enrollment (recommended)\n\n```bash\n# Mint an embedded session — host a 127.0.0.1 callback first\ncurl -s -X POST -H \"Authorization: Bearer $NVM_API_KEY\" -H \"Content-Type: application/json\" \\\n  -d '{ \"returnUrl\": \"http://127.0.0.1:<port>/callback\" }' \\\n  https://api.sandbox.nevermined.app/api/v1/embed/session\n```\n\nResponse:\n\n```json\n{\n  \"sessionToken\": \"eyJ...\",\n  \"userId\": \"user-...\",\n  \"userWallet\": \"0xabc...\",\n  \"apiKeyHash\": \"0x...\",\n  \"expiresAt\": \"2026-06-09T12:34:56.000Z\",\n  \"isReturnUrlAllowed\": true\n}\n```\n\nHave your human open the card-setup page (the card and its delegation attach to **your** account):\n\n```\nhttps://embed.nevermined.app/cards/setup?sessionToken=<sessionToken>&returnUrl=http://127.0.0.1:<port>/callback&state=<random>&provider=stripe\n```\n\nOn completion the browser redirects to your `returnUrl` with `paymentMethodId` and `delegationId`. **Store the `delegationId`.**\n\n> **Callback security.** Generate `state` as an unguessable random value and reject the callback unless the returned `state` matches it (binds the response to your request — CSRF guard). `paymentMethodId`/`delegationId` here — and `nvm_api_key` in the API-key flow (step 1) — arrive in the **query string**, the most-logged part of a request, so your `127.0.0.1` callback server must not log the request line, and the key belongs in a secret store, never on disk in the clear.\n\n> Can't host a localhost callback? Have your human enroll a card and create a delegation directly at [nevermined.app](https://nevermined.app) (Payment Methods → Enroll card → Delegate), then resume at step 4.\n\n### 3b. Create a delegation explicitly\n\n`provider`, `currency`, `spendingLimitCents`, and `durationSecs` are all **required** (no silent default for `provider` or `currency`). Use `currency: \"usdc\"` for `erc4337`, `\"usd\"` for card providers. `providerPaymentMethodId` is the `id` from `GET /payment-methods` (omit it for the default stablecoin smart account). The delegation is **plan-agnostic** unless you pass `planId`.\n\n```bash\n# Stablecoin / crypto — fully programmatic, no card, no human.\ncurl -s -X POST -H \"Authorization: Bearer $NVM_API_KEY\" -H \"Content-Type: application/json\" \\\n  -d '{ \"provider\": \"erc4337\", \"spendingLimitCents\": 10000, \"durationSecs\": 604800, \"currency\": \"usdc\" }' \\\n  https://api.sandbox.nevermined.app/api/v1/delegation/create\n\n# Card (set a fresh budget on an already-enrolled card)\ncurl -s -X POST -H \"Authorization: Bearer $NVM_API_KEY\" -H \"Content-Type: application/json\" \\\n  -d '{\n        \"provider\": \"stripe\",\n        \"providerPaymentMethodId\": \"pm_1Q...\",\n        \"spendingLimitCents\": 10000,\n        \"durationSecs\": 604800,\n        \"currency\": \"usd\"\n      }' \\\n  https://api.sandbox.nevermined.app/api/v1/delegation/create\n```\n\nResponse:\n\n```json\n{ \"delegationId\": \"del_...\", \"delegationToken\": \"eyJ...\" }\n```\n\n> **Visa needs browser-produced proofs.** `provider: \"visa\"` *is* accepted by `delegation/create`, but only together with `consumerPrompt` + `assuranceData` from a Visa WebAuthn ceremony; without them it's rejected with `BCK.VISA.0014` (\"requires consumerPrompt and assuranceData\"). An autonomous agent can't generate `assuranceData`, so create Visa delegations in the webapp and reuse the `delegationId`.\n\n---\n\n## 4. Buy access via x402\n\nTwo calls. **x402 is the default buy flow for both rails** — crypto and card are identical except `scheme`/`network`; the facilitator charges the right method (on-chain against your delegation for crypto, the card for fiat).\n\n### 4a. Get an access token\n\n```bash\ncurl -s -X POST -H \"Authorization: Bearer $NVM_API_KEY\" -H \"Content-Type: application/json\" \\\n  -d '{\n        \"accepted\": { \"scheme\": \"nvm:erc4337\", \"network\": \"eip155:84532\", \"planId\": \"<PLAN_ID>\" },\n        \"delegationConfig\": { \"delegationId\": \"<YOUR_DELEGATION_ID>\" }\n      }' \\\n  https://api.sandbox.nevermined.app/api/v1/x402/permissions\n# → { \"accessToken\": \"eyJ...\" }\n```\n\n- **Card:** `\"scheme\": \"nvm:card-delegation\"`, `\"network\": \"stripe\"` (or `braintree`/`visa`).\n- **Create-first only:** always create the delegation via `/delegation/create` (step 3b) and pass its `delegationId` here. Inline create-on-the-fly (a `delegationConfig` without a `delegationId`) is **deprecated** and emits a runtime deprecation warning.\n- **Field rename:** the response field is `accessToken`; pass that value as `x402AccessToken` in `/settle` and `/verify` below.\n- **Don't know the plan's scheme?** `GET {API_BASE}/api/v1/protocol/plans/<PLAN_ID>` (public) returns the plan's metadata and pricing.\n\n### 4b. Settle (the proof of purchase)\n\n```bash\ncurl -s -X POST -H \"Authorization: Bearer $NVM_API_KEY\" -H \"Content-Type: application/json\" \\\n  -d '{\n        \"paymentRequired\": {\n          \"x402Version\": 2,\n          \"resource\": { \"url\": \"<PLAN_OR_RESOURCE_URL>\" },\n          \"accepts\": [ { \"scheme\": \"nvm:erc4337\", \"network\": \"eip155:84532\", \"planId\": \"<PLAN_ID>\", \"extra\": {} } ],\n          \"extensions\": {}\n        },\n        \"x402AccessToken\": \"<accessToken>\"\n      }' \\\n  https://api.sandbox.nevermined.app/api/v1/x402/settle\n```\n\nResponse (`X402SettleResponseDto`):\n\n```json\n{\n  \"success\": true,\n  \"payer\": \"0xabc...\",\n  \"transaction\": \"0xdef...\",\n  \"network\": \"eip155:84532\",\n  \"billingModel\": \"credits\",\n  \"creditsRedeemed\": \"1\",\n  \"remainingBalance\": \"999\"\n}\n```\n\n**Your proof of payment depends on `billingModel`**, which is always present — read it before the credit fields:\n\n- `\"credits\"` — `success: true` **and** `creditsRedeemed > 0`, with `remainingBalance` as the balance left.\n- `\"pay-as-you-go\"` — `success: true` **and** a non-empty `orderTx` (fiat rails) or `transaction` (crypto rails). These plans hold no credit balance, so a successful charge still returns `creditsRedeemed: \"0\"` and `remainingBalance: \"0\"`:\n\n```json\n{\n  \"success\": true,\n  \"transaction\": \"pi_3U6tgrBYvSRKcV421ehH4bnX\",\n  \"network\": \"stripe\",\n  \"billingModel\": \"pay-as-you-go\",\n  \"creditsRedeemed\": \"0\",\n  \"remainingBalance\": \"0\",\n  \"orderTx\": \"pi_3U6tgrBYvSRKcV421ehH4bnX\"\n}\n```\n\nChecking `creditsRedeemed > 0` on such a plan reports a real charge as a decline — and on a card rail that invites a retry of a payment that already went through. Both fields are **strings**, so `\"0\"` is truthy while `Number(\"0\") > 0` is false.\n\nIf the response carries **no `billingModel` at all**, the deployment predates the discriminator: apply the `credits` rule, and never read a missing discriminator as pay-as-you-go.\n\nFor a plan top-up with no protected endpoint, set `resource.url` to the plan's own URL — `{API_BASE}/api/v1/protocol/plans/<PLAN_ID>`.\n\n### 4c. Dry-run (optional)\n\n```bash\ncurl -s -X POST -H \"Authorization: Bearer $NVM_API_KEY\" -H \"Content-Type: application/json\" \\\n  -d '{ \"paymentRequired\": { ... same as settle ... }, \"x402AccessToken\": \"<accessToken>\" }' \\\n  https://api.sandbox.nevermined.app/api/v1/x402/verify\n# → { \"isValid\": true }\n```\n\n### 4d. Buying from a protected agent (most common)\n\nIf you're calling an x402-protected agent/service rather than topping up a plan, you don't build `paymentRequired` yourself:\n\n1. Call the agent's endpoint with no token → it returns `402` with a `payment-required` header (base64 JSON). That decoded object **is** your `paymentRequired`.\n2. Get an access token (step 4a) using its `accepts[0]` scheme/network/planId.\n3. Retry the request with header `payment-signature: <accessToken>`. The agent verifies and settles for you and returns `200` with a `payment-response` receipt header (base64 JSON of the settle response above).\n\nCommon errors (read the message — code semantics differ slightly between the OpenAPI examples and the backend error registry, so recover by the message, not the number alone): `BCK.X402.0001` — can't generate the token: unknown/invalid `planId` or `agentId` (the agent may not exist). `BCK.X402.0002` — plan not found (often the wrong environment). `BCK.X402.0003` — token rejected: it's expired/invalid **or** the plan isn't linked to the agent — regenerate the token, and if it persists verify the plan↔agent association rather than looping on token regeneration.\n\n---\n\n## 5. Check your purchases & credits (buyer)\n\n```bash\n# Remaining credits on a plan you hold\ncurl -s -H \"Authorization: Bearer $NVM_API_KEY\" \\\n  https://api.sandbox.nevermined.app/api/v1/protocol/plans/<PLAN_ID>/balance/<YOUR_ADDRESS>\n# → { planId, planName, planType, isSubscriber, holderAddress, balance, pricePerCredit, creditsContract }\n\n# Your delegations + remaining budget\ncurl -s -H \"Authorization: Bearer $NVM_API_KEY\" \\\n  https://api.sandbox.nevermined.app/api/v1/delegation\n# → { totalResults, page, offset, delegations: [\n#      { delegationId, provider, status, spendingLimitCents, amountSpentCents,\n#        remainingBudgetCents, currency, transactionCount, expiresAt, createdAt } ] }\n#   `status` is \"Active\" | \"Expired\" | \"Exhausted\".\n\n# One delegation's charges\ncurl -s -H \"Authorization: Bearer $NVM_API_KEY\" \\\n  https://api.sandbox.nevermined.app/api/v1/delegation/<DELEGATION_ID>/transactions\n# → { totalResults, page, offset, transactions: [ { id, delegationId, providerTransactionId,\n#        amountCents, currency, status, failureReason, feeCents, feeAtomic, feeBps, feeReleased, createdAt } ] }\n#   `amountCents` is the COMBINED cap deduction. On a Router-routed payment that is the merchant\n#   leg plus Nevermined's routing fee, broken out as `feeCents` (string) / `feeAtomic` (string) /\n#   `feeBps` (number); `feeReleased` (boolean) means the fee was credited back and `amountCents`\n#   is ALREADY net of it. All four read zero/false on a card or crypto row, which pay no routing fee.\n```\n\n`YOUR_ADDRESS` is your account wallet: the `id`/address of your `erc4337` payment method from `GET /payment-methods` (crypto path), or the `userWallet` returned by `POST /embed/session`.\n\n---\n\n## 6. Register a plan + agent (seller) — use the SDK\n\nRegistration's `priceConfig`/`creditsConfig` are low-level on-chain structures; build them with SDK helpers rather than by hand. See `payment-plans.md`. The REST endpoints are `POST /api/v1/protocol/plans`, `POST /api/v1/protocol/agents`, and `POST /api/v1/protocol/agents/plans` (atomic), but they expect those fully-formed config objects.\n\n---\n\n## 7. Check your agents' status & revenue (seller)\n\nSee `seller-operations.md` for the full set of analytics and building-block queries (revenue, MRR, usage, customers, plus the any-tier `/protocol/plans` and `/protocol/agents` lists).\n\n---\n\n## Quick reference — endpoints\n\n| Flow | Method + path | Auth |\n|---|---|---|\n| List payment methods | `GET /api/v1/payment-methods` | API key |\n| Mint embed session | `POST /api/v1/embed/session` | API key |\n| Create delegation | `POST /api/v1/delegation/create` | API key |\n| List delegations | `GET /api/v1/delegation` | API key |\n| Delegation transactions | `GET /api/v1/delegation/{id}/transactions` | API key |\n| Get x402 token | `POST /api/v1/x402/permissions` | API key |\n| Settle | `POST /api/v1/x402/settle` | API key |\n| Verify (dry-run) | `POST /api/v1/x402/verify` | API key |\n| Plan balance | `GET /api/v1/protocol/plans/{planId}/balance/{address}` | API key |\n| My plans / agents | `GET /api/v1/protocol/plans` · `GET /api/v1/protocol/agents` | API key |\n| Register plan / agent / both | `POST /api/v1/protocol/plans` · `/agents` · `/agents/plans` | API key |\n| Org analytics | `GET /api/v1/organizations/{orgId}/analytics/{revenue,mrr,usage,customers}` | API key + Premium |\n\nFile v1.0.10:references/client-integration.md\n\n# Client-Side Integration (Subscriber Flow)\n\nHow to purchase plans, generate x402 tokens, and call payment-protected APIs as a subscriber.\n\n> ⚠️ **Run examples in `sandbox` first.** `orderPlan` charges money in `live`, and `delegationConfig` grants the platform pre-authorized spending up to `spendingLimitCents` for `durationSecs` seconds. Examples below use a small sandbox-friendly budget (`100¢` over `1h`); raise per use-case after explicit review.\n\n## Overview\n\nAs a subscriber (consumer of a paid API/agent), you:\n1. Order a payment plan\n2. Check your credit balance\n3. Generate an x402 access token\n4. Send requests with the `payment-signature` header\n5. Decode the settlement receipt from the `payment-response` header\n\n## Pure-REST purchase (no SDK)\n\nAn autonomous agent can complete the whole subscriber flow with plain HTTP — no SDK install. Send `Authorization: Bearer $NVM_API_KEY` on each call.\n\n```bash\n# 1. Get an x402 access token (create the delegation first via /delegation/create, then pass its delegationId)\ncurl -s -X POST -H \"Authorization: Bearer $NVM_API_KEY\" -H \"Content-Type: application/json\" \\\n  -d '{ \"accepted\": { \"scheme\": \"nvm:erc4337\", \"network\": \"eip155:84532\", \"planId\": \"<PLAN_ID>\" },\n        \"delegationConfig\": { \"delegationId\": \"<DELEGATION_ID>\" } }' \\\n  https://api.sandbox.nevermined.app/api/v1/x402/permissions\n# → { \"accessToken\": \"...\" }\n\n# 2. Settle (proof of purchase). For a plan top-up, resource.url is the plan URL.\ncurl -s -X POST -H \"Authorization: Bearer $NVM_API_KEY\" -H \"Content-Type: application/json\" \\\n  -d '{ \"paymentRequired\": { \"x402Version\": 2, \"resource\": { \"url\": \"<PLAN_OR_RESOURCE_URL>\" },\n          \"accepts\": [ { \"scheme\": \"nvm:erc4337\", \"network\": \"eip155:84532\", \"planId\": \"<PLAN_ID>\", \"extra\": {} } ],\n          \"extensions\": {} },\n        \"x402AccessToken\": \"<accessToken>\" }' \\\n  https://api.sandbox.nevermined.app/api/v1/x402/settle\n# → { \"success\": true, \"billingModel\": \"credits\", \"creditsRedeemed\": \"1\", \"remainingBalance\": \"999\", \"transaction\": \"0x...\" }\n```\n\n- **Card payment:** switch `scheme` to `nvm:card-delegation` and `network` to `stripe` (or `braintree`/`visa`) in both calls.\n- **Calling a protected agent directly:** skip building `paymentRequired` — send the access token as the `payment-signature` header; the agent settles for you and returns the receipt in the `payment-response` header.\n- **Proof of purchase — read `billingModel` first.** On a `credits` plan it is `success: true` and `creditsRedeemed > 0`. On a `pay-as-you-go` plan there is no credit balance, so `creditsRedeemed` and `remainingBalance` are always the string `\"0\"` even on a successful charge; the proof is `success: true` plus a non-empty `orderTx` (fiat) or `transaction` (crypto). Never gate on `creditsRedeemed` alone — on a card rail it reports a real charge as a decline and invites a retry. If `billingModel` is missing entirely the deployment predates it: apply the `credits` rule.\n\nFull runbook with API-key retrieval, card enrollment, and status checks: `autonomous-operations.md`.\n\n## Order a Plan and Get a Token\n\n### TypeScript\n\n```typescript\nimport { Payments } from '@nevermined-io/payments'\n\nconst payments = Payments.getInstance({\n  nvmApiKey: process.env.NVM_API_KEY!,\n  environment: 'sandbox'\n})\n\n// Order the plan\nawait payments.plans.orderPlan(PLAN_ID)\n\n// Check balance — getPlanBalance returns a PlanBalance object\nconst planBalance = await payments.plans.getPlanBalance(PLAN_ID)\nconsole.log(`Credits remaining: ${planBalance.balance}`)        // bigint\nconsole.log(`Subscriber: ${planBalance.isSubscriber}`)\n\n// Create the delegation first (provider + currency required), then request the token by delegationId.\nconst delegation = await payments.delegation.createDelegation({\n  provider: 'erc4337', spendingLimitCents: 100, durationSecs: 3600, currency: 'usdc'\n})\nconst { accessToken } = await payments.x402.getX402AccessToken(PLAN_ID, AGENT_ID, {\n  delegationConfig: { delegationId: delegation.delegationId }\n})\n```\n\n### Python\n\n```python\nimport os\nfrom payments_py import Payments, PaymentOptions\nfrom payments_py.x402 import CreateDelegationPayload, DelegationConfig, X402TokenOptions\n\npayments = Payments.get_instance(\n    PaymentOptions(nvm_api_key=os.environ[\"NVM_API_KEY\"], environment=\"sandbox\")\n)\n\n# Order the plan\npayments.plans.order_plan(plan_id)\n\n# Check balance — get_plan_balance returns a PlanBalance object\nplan_balance = payments.plans.get_plan_balance(plan_id)\nprint(f\"Credits remaining: {plan_balance.balance}\")\nprint(f\"Subscriber: {plan_balance.is_subscriber}\")\n\n# Create the delegation first (provider + currency required), then request the token by delegation_id.\ndelegation = payments.delegation.create_delegation(\n    CreateDelegationPayload(\n        provider=\"erc4337\", spending_limit_cents=100, duration_secs=3600, currency=\"usdc\"\n    )\n)\ntoken_res = payments.x402.get_x402_access_token(\n    plan_id, agent_id,\n    token_options=X402TokenOptions(\n        delegation_config=DelegationConfig(delegation_id=delegation.delegation_id)\n    )\n)\naccess_token = token_res[\"accessToken\"]\n```\n\n## Automatic Credit Top-Ups\n\nWhen the access token carries a `delegationConfig`, the facilitator tops up the subscriber's credits automatically — no manual balance-check-then-`orderPlan` loop.\n\n- The top-up fires at **settlement** (when a paid request is consumed), **not** when `getX402AccessToken` is called. Generating the token only pre-authorizes the spend; no credits are bought until the balance is actually short.\n- **Crypto (`nvm:erc4337`)**: the facilitator executes an on-chain `order` against the subscriber's smart account.\n- **Fiat (`nvm:card-delegation`)**: the facilitator charges the enrolled card off-session — built into the card delegation, no extra parameter.\n- Every top-up is bounded by the delegation's `spendingLimitCents`. When that's exhausted or the delegation expires, settlement fails and the request returns `402`.\n- Create the delegation first and reuse it by passing `delegationConfig.delegationId` (passing `spendingLimitCents` + `durationSecs` inline still works but is deprecated and emits a runtime warning).\n- In A2A pipelines, handle `402`/settlement failures explicitly — surface a clear payment error rather than retrying indefinitely.\n\nFull guide: [Automatic Credit Top-Ups](https://nevermined.ai/docs/integrate/patterns/top-up).\n\n## Call a Protected HTTP API\n\n### TypeScript\n\n```typescript\nimport { Payments } from '@nevermined-io/payments'\nimport { X402_HEADERS } from '@nevermined-io/payments/express'\n\nconst payments = Payments.getInstance({\n  nvmApiKey: process.env.NVM_API_KEY!,\n  environment: 'sandbox'\n})\n\nasync function callProtectedAPI() {\n  const SERVER_URL = 'http://localhost:3000'\n\n  // Step 1: Request without token → 402\n  const response1 = await fetch(`${SERVER_URL}/ask`, {\n    method: 'POST',\n    headers: { 'Content-Type': 'application/json' },\n    body: JSON.stringify({ query: 'What is 2+2?' })\n  })\n\n  if (response1.status === 402) {\n    // Step 2: Decode payment requirements\n    const paymentRequired = JSON.parse(\n      Buffer.from(\n        response1.headers.get(X402_HEADERS.PAYMENT_REQUIRED)!,\n        'base64'\n      ).toString()\n    )\n\n    const { planId, extra } = paymentRequired.accepts[0]\n    const agentId = extra?.agentId\n\n    // Step 3: Create the delegation first, then generate the x402 token by delegationId\n    const delegation = await payments.delegation.createDelegation({\n      provider: 'erc4337', spendingLimitCents: 100, durationSecs: 3600, currency: 'usdc'\n    })\n    const { accessToken } = await payments.x402.getX402AccessToken(planId, agentId, {\n      delegationConfig: { delegationId: delegation.delegationId }\n    })\n\n    // Step 4: Request with token → 200\n    const response2 = await fetch(`${SERVER_URL}/ask`, {\n      method: 'POST',\n      headers: {\n        'Content-Type': 'application/json',\n        [X402_HEADERS.PAYMENT_SIGNATURE]: accessToken\n      },\n      body: JSON.stringify({ query: 'What is 2+2?' })\n    })\n\n    const data = await response2.json()\n    console.log('Response:', data.response)\n\n    // Step 5: Decode settlement receipt\n    const settlement = JSON.parse(\n      Buffer.from(\n        response2.headers.get(X402_HEADERS.PAYMENT_RESPONSE)!,\n        'base64'\n      ).toString()\n    )\n    // On a pay-as-you-go plan `creditsRedeemed` is always '0' — see \"Proof of\n    // purchase\" above; the charge reference is `orderTx` / `transaction`.\n    console.log('Billing model:', settlement.billingModel)\n    console.log('Credits used:', settlement.creditsRedeemed)\n  }\n}\n```\n\n### Python\n\n```python\nimport os\nimport base64\nimport json\nimport httpx\nfrom payments_py import Payments, PaymentOptions\nfrom payments_py.x402 import CreateDelegationPayload, DelegationConfig, X402TokenOptions\n\npayments = Payments.get_instance(\n    PaymentOptions(\n        nvm_api_key=os.environ[\"NVM_API_KEY\"],\n        environment=os.environ.get(\"NVM_ENVIRONMENT\", \"sandbox\")\n    )\n)\n\ndef call_protected_api():\n    SERVER_URL = \"http://localhost:3000\"\n\n    with httpx.Client(timeout=60.0) as client:\n        # Step 1: Request without token → 402\n        response1 = client.post(\n            f\"{SERVER_URL}/ask\",\n            json={\"query\": \"What is 2+2?\"}\n        )\n\n        if response1.status_code == 402:\n            # Step 2: Decode payment requirements\n            payment_required = json.loads(\n                base64.b64decode(\n                    response1.headers.get(\"payment-required\")\n                ).decode()\n            )\n\n            plan_id = payment_required[\"accepts\"][0][\"planId\"]\n            agent_id = payment_required[\"accepts\"][0].get(\"extra\", {}).get(\"agentId\")\n\n            # Step 3: Create the delegation first, then generate the token by delegation_id\n            delegation = payments.delegation.create_delegation(\n                CreateDelegationPayload(\n                    provider=\"erc4337\", spending_limit_cents=100,\n                    duration_secs=3600, currency=\"usdc\"\n                )\n            )\n            token_result = payments.x402.get_x402_access_token(\n                plan_id, agent_id,\n                token_options=X402TokenOptions(\n                    delegation_config=DelegationConfig(\n                        delegation_id=delegation.delegation_id\n                    )\n                )\n            )\n            access_token = token_result[\"accessToken\"]\n\n            # Step 4: Request with token → 200\n            response2 = client.post(\n                f\"{SERVER_URL}/ask\",\n                headers={\"payment-signature\": access_token},\n                json={\"query\": \"What is 2+2?\"}\n            )\n\n            data = response2.json()\n            print(f\"Response: {data['response']}\")\n\n            # Step 5: Decode settlement receipt\n            settlement = json.loads(\n                base64.b64decode(\n                    response2.headers.get(\"payment-response\")\n                ).decode()\n            )\n            # On a pay-as-you-go plan creditsRedeemed is always \"0\" — see \"Proof\n            # of purchase\" above; the charge reference is orderTx / transaction.\n            print(f\"Billing model: {settlement.get('billingModel')}\")\n            print(f\"Credits used: {settlement.get('creditsRedeemed')}\")\n\nif __name__ == \"__main__\":\n    call_protected_api()\n```\n\n## Connect to a Protected MCP Server\n\n### TypeScript\n\n```typescript\nimport { Client } from \"@modelcontextprotocol/sdk/client\"\nimport { StreamableHTTPClientTransport } from \"@modelcontextprotocol/sdk/client/streamableHttp\"\nimport { decodeAccessToken } from \"@nevermined-io/payments\"\n\nconst delegation = await payments.delegation.createDelegation({\n  provider: 'erc4337', spendingLimitCents: 100, durationSecs: 3600, currency: 'usdc'\n})\nconst { accessToken } = await payments.x402.getX402AccessToken(planId, agentId, {\n  delegationConfig: { delegationId: delegation.delegationId }\n})\n\n// Nevermined MCP servers do not read the `payment-signature` header. The `/mcp`\n// endpoint requires `Authorization: Bearer <accessToken>`; the paywall prefers the\n// in-band `_meta[\"x402/payment\"]` payload (below) when present.\nconst transport = new StreamableHTTPClientTransport(\n  new URL(\"http://localhost:3000/mcp\"),\n  {\n    requestInit: {\n      headers: { Authorization: `Bearer ${accessToken}` }\n    }\n  }\n)\n\nconst client = new Client({ name: \"my-client\" })\nawait client.connect(transport)\n\nconst result = await client.callTool({\n  name: \"weather.today\",\n  arguments: { city: \"Madrid\" },\n  _meta: { \"x402/payment\": decodeAccessToken(accessToken) },\n})\n```\n\n## Call a Protected Strands Agent\n\n### Python\n\n```python\nfrom payments_py.x402 import CreateDelegationPayload, DelegationConfig, X402TokenOptions\nfrom payments_py.x402.strands import extract_payment_required\nfrom agent import agent, payments\n\n# Step 1: Call without token — triggers PaymentRequired\nresult = agent(\"Analyze sales trends\")\n\n# Step 2: Extract payment requirements\npayment_required = extract_payment_required(agent.messages)\n\nif payment_required:\n    chosen_plan = payment_required[\"accepts\"][0]\n    plan_id = chosen_plan[\"planId\"]\n    agent_id = (chosen_plan.get(\"extra\") or {}).get(\"agentId\")\n\n    # Step 3: Create the delegation first, then get the token by delegation_id\n    delegation = payments.delegation.create_delegation(\n        CreateDelegationPayload(\n            provider=\"erc4337\", spending_limit_cents=100,\n            duration_secs=3600, currency=\"usdc\"\n        )\n    )\n    token_response = payments.x402.get_x402_access_token(\n        plan_id, agent_id,\n        token_options=X402TokenOptions(\n            delegation_config=DelegationConfig(\n                delegation_id=delegation.delegation_id\n            )\n        )\n    )\n    access_token = token_response[\"accessToken\"]\n\n    # Step 4: Retry with token\n    state = {\"payment_token\": access_token}\n    result = agent(\"Analyze sales trends\", invocation_state=state)\n```\n\n## Environment Variables\n\n```bash\nNVM_API_KEY=sandbox:your-subscriber-api-key\nNVM_ENVIRONMENT=sandbox\n```\n\nFile v1.0.10:references/customer-onboarding.md\n\n# White-label Customer Onboarding\n\nHow an **organization** provisions Nevermined accounts for *its own customers* — under its brand, without the customer ever creating a Nevermined login. Companion to **Track A · A8** in `SKILL.md`.\n\n> **Admin-only.** Authenticate with your **organization admin** API key. One endpoint does both member and customer provisioning — the outcome is the `as` field, not a second route.\n\n## The endpoint\n\n```\nPOST /api/v1/organizations/account\nAuthorization: Bearer <ORG_ADMIN_API_KEY>\nContent-Type: application/json\n\n{ \"email\": \"customer@example.com\", \"as\": \"customer\" }\n```\n\n`as: \"customer\"` provisions a **customer** (no member seat, recorded in the Customers CRM, returns a usable scoped key). Omit `as` (or `as: \"member\"`) for the unchanged member-enrolment behaviour.\n\n## Three outcomes (by email provenance)\n\n| The email is… | HTTP | `walletResult` |\n|---|---|---|\n| **New** | `201` | `{ nvmApiKey, userId, userWallet, isCustomer: true, customerRecorded }` — the **usable** key |\n| **Already your customer** (renewal) | `201` | same shape — the scoped key re-issued |\n| **An existing account you don't own** | `202` | `{ consentRequired: true }` — **no key, no identity**; a consent email was sent to the owner |\n\nThe `202` case is deliberately opaque: you can't attach someone else's account to your org, and the response never reveals whether/who the account belongs to (no enumeration oracle). Retry with the same email once the owner approves the emailed challenge.\n\n```bash\n# New / returning customer → usable key\ncurl -s -XPOST -H \"Authorization: Bearer $ORG_ADMIN_API_KEY\" -H \"Content-Type: application/json\" \\\n  -d '{\"email\":\"customer@example.com\",\"as\":\"customer\"}' \\\n  https://api.sandbox.nevermined.app/api/v1/organizations/account\n# → 201 { \"success\": true, \"message\": \"Customer onboarded\",\n#         \"walletResult\": { \"nvmApiKey\": \"sandbox:...\", \"userId\": \"...\", \"userWallet\": \"0x...\",\n#                           \"isCustomer\": true, \"customerRecorded\": true } }\n\n# Existing non-owned account → consent pending (opaque)\n# → 202 { \"success\": true, \"message\": \"Account already exists — a consent email was sent ...\",\n#         \"walletResult\": { \"consentRequired\": true } }\n```\n\n## SDK\n\nThe SDKs wrap the same call and normalise the two shapes.\n\n```typescript\n// TypeScript — @nevermined-io/payments\nconst result = await payments.organizations.onboardCustomer('customer@example.com')\nif (result.consentRequired) {\n  // 202: retry once the owner approves the emailed challenge.\n} else {\n  // result.nvmApiKey is the usable, scoped key. Act for the customer with it:\n  const customer = Payments.getInstance({ nvmApiKey: result.nvmApiKey, environment: 'sandbox' })\n}\n```\n\n```python\n# Python — payments_py\nresult = payments.organizations.onboard_customer(\"customer@example.com\")\nif result.consent_required:\n    ...  # retry after the owner consents\nelse:\n    customer = Payments.get_instance(\n        PaymentOptions(nvm_api_key=result.nvm_api_key, environment=\"sandbox\")\n    )\n```\n\n## The credential\n\nThe key returned for a customer is intentionally **narrow**:\n\n- **Can:** purchase plans + redeem credits (`order`, `burn`) — everything to pay for and use your agents on the customer's behalf (Track A · A4/A5).\n- **Cannot:** register agents or mint credits — builder-side capabilities stay with your org's members.\n- **Short-lived** (~30 days) and **revocable.** Store it server-side; re-onboard the same email to refresh it. Never expose it to the browser.\n\n## Quick reference\n\n| Step | Method + path | Auth |\n|---|---|---|\n| Onboard a customer | `POST /organizations/account` body `{ email, as: \"customer\" }` | Org admin key |\n| Act for the customer | re-init the SDK with `walletResult.nvmApiKey`, then A4/A5 | The scoped customer key |\n\nThe UI counterpart (embed checkout/enrollment as signed iframes) is `POST /embed/session` — see `references/autonomous-operations.md` §3.\n\nFile v1.0.10:references/express-integration.md\n\n# Express.js Integration\n\nAdd x402 payment protection to Express.js APIs using `paymentMiddleware` from `@nevermined-io/payments/express`.\n\n## Installation\n\n```bash\nnpm install @nevermined-io/payments express\n```\n\n## Quick Start\n\n```typescript\nimport express from 'express'\nimport { Payments } from '@nevermined-io/payments'\nimport { paymentMiddleware } from '@nevermined-io/payments/express'\n\nconst app = express()\napp.use(express.json())\n\nconst payments = Payments.getInstance({\n  nvmApiKey: process.env.NVM_API_KEY!,\n  environment: process.env.NVM_ENVIRONMENT === 'live' ? 'live' : 'sandbox'\n})\n\n// Protect routes with one line\napp.use(\n  paymentMiddleware(payments, {\n    'POST /ask': {\n      planId: process.env.NVM_PLAN_ID!,\n      credits: 1\n    }\n  })\n)\n\n// Route handler — no payment logic needed\napp.post('/ask', async (req, res) => {\n  const { query } = req.body\n  const response = await generateAIResponse(query)\n  res.json({ response })\n})\n\napp.listen(3000, () => console.log('Server running on http://localhost:3000'))\n```\n\nThe middleware automatically:\n- Returns `402` with `payment-required` header when no token is provided\n- Verifies the x402 token via the Nevermined facilitator\n- Burns credits after request completion\n- Returns `payment-response` header with settlement receipt\n\n## Route Configuration\n\n### Fixed Credits\n\n```typescript\npaymentMiddleware(payments, {\n  'POST /ask': { planId: PLAN_ID, credits: 1 },\n  'POST /generate': { planId: PLAN_ID, credits: 5 }\n})\n```\n\n### Dynamic Credits\n\nCalculate credits based on request/response:\n\n```typescript\npaymentMiddleware(payments, {\n  'POST /generate': {\n    planId: PLAN_ID,\n    credits: (req, res) => {\n      const tokens = res.locals.tokenCount || 100\n      return Math.ceil(tokens / 100)\n    }\n  }\n})\n```\n\n### Path Parameters\n\n```typescript\npaymentMiddleware(payments, {\n  'GET /users/:id': { planId: PLAN_ID, credits: 1 },\n  'POST /agents/:agentId/task': { planId: PLAN_ID, credits: 2 }\n})\n```\n\n### With Agent ID\n\n```typescript\npaymentMiddleware(payments, {\n  'POST /task': {\n    planId: PLAN_ID,\n    agentId: AGENT_ID,  // Required for plans with multiple agents\n    credits: 5\n  }\n})\n```\n\n## Middleware Options\n\n```typescript\npaymentMiddleware(payments, routes, {\n  tokenHeader: 'payment-signature',\n\n  onBeforeVerify: (req, paymentRequired) => {\n    console.log(`Verifying payment for ${req.path}`)\n  },\n\n  onAfterVerify: (req, verification) => {\n    const agentRequest = verification.agentRequest\n    if (agentRequest) {\n      console.log(`Agent: ${agentRequest.agentName}`)\n    }\n  },\n\n  onAfterSettle: (req, creditsUsed, settlement) => {\n    console.log(`Settled ${creditsUsed} credits, tx: ${settlement.transaction}`)\n  },\n\n  onPaymentError: (error, req, res) => {\n    res.status(402).json({ error: error.message })\n  }\n})\n```\n\n## Complete Example\n\n```typescript\nimport express from 'express'\nimport OpenAI from 'openai'\nimport { Payments } from '@nevermined-io/payments'\nimport { paymentMiddleware } from '@nevermined-io/payments/express'\n\nconst app = express()\napp.use(express.json())\n\nconst payments = Payments.getInstance({\n  nvmApiKey: process.env.NVM_API_KEY!,\n  environment: 'sandbox'\n})\n\nconst openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY })\n\napp.use(\n  paymentMiddleware(payments, {\n    'POST /ask': {\n      planId: process.env.NVM_PLAN_ID!,\n      credits: 1\n    }\n  }, {\n    onBeforeVerify: (req) => {\n      console.log(`[Payment] Verifying request to ${req.path}`)\n    },\n    onAfterSettle: (req, credits) => {\n      console.log(`[Payment] Settled ${credits} credits`)\n    }\n  })\n)\n\napp.post('/ask', async (req, res) => {\n  const { query } = req.body\n  const completion = await openai.chat.completions.create({\n    model: 'gpt-4o-mini',\n    messages: [{ role: 'user', content: query }]\n  })\n  res.json({ response: completion.choices[0]?.message?.content })\n})\n\napp.get('/health', (req, res) => {\n  res.json({ status: 'ok' })\n})\n\nconst PORT = process.env.PORT || 3000\napp.listen(PORT, () => {\n  console.log(`Agent running on http://localhost:${PORT}`)\n})\n```\n\n## Environment Variables\n\n```bash\nNVM_API_KEY=sandbox:your-api-key\nNVM_ENVIRONMENT=sandbox\nNVM_PLAN_ID=your-plan-id\nOPENAI_API_KEY=sk-your-openai-api-key\nPORT=3000\n```\n\n## Tutorial\n\nComplete working example: [github.com/nevermined-io/tutorials/tree/main/http-simple-agent-ts](https://github.com/nevermined-io/tutorials/tree/main/http-simple-agent-ts)\n\nFile v1.0.10:references/fastapi-integration.md\n\n# FastAPI Integration\n\nAdd x402 payment protection to FastAPI applications using `PaymentMiddleware` from `payments_py.x402.fastapi`.\n\n## Installation\n\n```bash\npip install payments-py[fastapi] fastapi uvicorn\n```\n\nThe `[fastapi]` extra installs FastAPI and Starlette dependencies required for the middleware.\n\n## Quick Start\n\n```python\nimport os\nfrom fastapi import FastAPI, Request\nfrom payments_py import Payments, PaymentOptions\nfrom payments_py.x402.fastapi import PaymentMiddleware\n\napp = FastAPI()\n\npayments = Payments.get_instance(\n    PaymentOptions(\n        nvm_api_key=os.environ[\"NVM_API_KEY\"],\n        environment=\"live\" if os.environ.get(\"ENV\") == \"production\" else \"sandbox\"\n    )\n)\n\n# Protect routes with one line\napp.add_middleware(\n    PaymentMiddleware,\n    payments=payments,\n    routes={\n        \"POST /ask\": {\"plan_id\": os.environ[\"NVM_PLAN_ID\"], \"credits\": 1}\n    }\n)\n\n# Route handler — no payment logic needed\n@app.post(\"/ask\")\nasync def ask(request: Request):\n    body = await request.json()\n    response = await generate_ai_response(body.get(\"query\"))\n    return {\"response\": response}\n\nif __name__ == \"__main__\":\n    import uvicorn\n    uvicorn.run(app, host=\"0.0.0.0\", port=3000)\n```\n\nThe middleware automatically:\n- Returns `402` with `payment-required` header when no token is provided\n- Verifies the x402 token via the Nevermined facilitator\n- Burns credits after request completion\n- Returns `payment-response` header with settlement receipt\n\n## Route Configuration\n\n### Fixed Credits\n\n```python\napp.add_middleware(\n    PaymentMiddleware,\n    payments=payments,\n    routes={\n        \"POST /ask\": {\"plan_id\": PLAN_ID, \"credits\": 1},\n        \"POST /generate\": {\"plan_id\": PLAN_ID, \"credits\": 5}\n    }\n)\n```\n\n### Dynamic Credits\n\n```python\nasync def calculate_credits(request: Request) -> int:\n    \"\"\"Charge based on requested token count.\"\"\"\n    body = await request.json()\n    max_tokens = body.get(\"max_tokens\", 100)\n    return max(1, max_tokens // 100)\n\napp.add_middleware(\n    PaymentMiddleware,\n    payments=payments,\n    routes={\n        \"POST /generate\": {\n            \"plan_id\": PLAN_ID,\n            \"credits\": calculate_credits  # Pass function instead of int\n        }\n    }\n)\n```\n\nSync functions also work:\n\n```python\napp.add_middleware(\n    PaymentMiddleware,\n    payments=payments,\n    routes={\n        \"POST /analyze\": {\n            \"plan_id\": PLAN_ID,\n            \"credits\": lambda req: 5 if req.headers.get(\"priority\") == \"high\" else 1\n        }\n    }\n)\n```\n\n### Path Parameters\n\n```python\napp.add_middleware(\n    PaymentMiddleware,\n    payments=payments,\n    routes={\n        \"GET /users/:id\": {\"plan_id\": PLAN_ID, \"credits\": 1},\n        \"POST /agents/:agentId/task\": {\"plan_id\": PLAN_ID, \"credits\": 2}\n    }\n)\n```\n\n### With Agent ID\n\n```python\napp.add_middleware(\n    PaymentMiddleware,\n    payments=payments,\n    routes={\n        \"POST /task\": {\n            \"plan_id\": PLAN_ID,\n            \"agent_id\": AGENT_ID,  # Required for plans with multiple agents\n            \"credits\": 5\n        }\n    }\n)\n```\n\n### Using RouteConfig\n\n```python\nfrom payments_py.x402.fastapi import PaymentMiddleware, RouteConfig\n\napp.add_middleware(\n    PaymentMiddleware,\n    payments=payments,\n    routes={\n        \"POST /ask\": RouteConfig(\n            plan_id=PLAN_ID,\n            credits=1,\n            agent_id=AGENT_ID,\n            network=\"eip155:84532\"\n        )\n    }\n)\n```\n\n## Middleware Options\n\nAll hooks are awaited internally — they MUST be `async def` (or any callable returning an `Awaitable`). Sync functions / lambdas will raise a `TypeError: object NoneType can't be used in 'await' expression` at request time.\n\n```python\nfrom payments_py.x402.fastapi import PaymentMiddleware, PaymentMiddlewareOptions\n\nasync def before_verify(request, payment_required):\n    print(f\"Verifying payment for {request.url.path}\")\n\nasync def after_verify(request, verification):\n    if verification.agent_request:\n        print(f\"Agent: {verification.agent_request.agent_name}\")\n\nasync def after_settle(request, credits_used, settlement):\n    print(f\"Settled {credits_used} credits\")\n\nasync def payment_error(error, request):\n    return None  # Return custom response or None to use default\n\napp.add_middleware(\n    PaymentMiddleware,\n    payments=payments,\n    routes={\"POST /ask\": {\"plan_id\": PLAN_ID, \"credits\": 1}},\n    options=PaymentMiddlewareOptions(\n        token_header=[\"payment-signature\"],\n        on_before_verify=before_verify,\n        on_after_verify=after_verify,\n        on_after_settle=after_settle,\n        on_payment_error=payment_error\n    )\n)\n```\n\n## Accessing Payment Context\n\nAfter verification, the payment context is available in `request.state.payment_context`:\n\n```python\nfrom payments_py.x402.fastapi import PaymentContext\n\n@app.post(\"/ask\")\nasync def ask(request: Request):\n    payment_context: PaymentContext = request.state.payment_context\n\n    token = payment_context.token\n    print(f\"Token: {token[:8]}…{token[-4:]}\")  # Never log full payment tokens — they are bearer credentials.\n    print(f\"Credits to settle: {payment_context.credits_to_settle}\")\n    print(f\"Agent request ID: {payment_context.agent_request_id}\")\n\n    if payment_context.agent_request:\n        print(f\"Agent: {payment_context.agent_request.agent_name}\")\n        print(f\"Balance: {payment_context.agent_request.balance}\")\n\n    body = await request.json()\n    response = await generate_ai_response(body.get(\"query\"))\n    return {\"response\": response}\n```\n\n## Complete Example\n\n```python\nimport os\nfrom dotenv import load_dotenv\n\nload_dotenv()\n\nfrom fastapi import FastAPI, Request\nfrom openai import OpenAI\nfrom payments_py import Payments, PaymentOptions\nfrom payments_py.x402.fastapi import PaymentMiddleware, PaymentMiddlewareOptions\n\napp = FastAPI(title=\"AI Agent with Nevermined Payments\")\n\npayments = Payments.get_instance(\n    PaymentOptions(\n        nvm_api_key=os.environ[\"NVM_API_KEY\"],\n        environment=os.environ.get(\"NVM_ENVIRONMENT\", \"sandbox\")\n    )\n)\nopenai_client = OpenAI(api_key=os.environ[\"OPENAI_API_KEY\"])\n\nPLAN_ID = os.environ[\"NVM_PLAN_ID\"]\n\n# Hooks must be async — see Middleware Options above\nasync def log_before_verify(req, pr):\n    print(f\"[Payment] Verifying request to {req.url.path}\")\n\nasync def log_after_settle(req, credits, settlement):\n    print(f\"[Payment] Settled {credits} credits\")\n\napp.add_middleware(\n    PaymentMiddleware,\n    payments=payments,\n    routes={\n        \"POST /ask\": {\"plan_id\": PLAN_ID, \"credits\": 1}\n    },\n    options=PaymentMiddlewareOptions(\n        on_before_verify=log_before_verify,\n        on_after_settle=log_after_settle,\n    )\n)\n\n@app.post(\"/ask\")\nasync def ask(request: Request):\n    body = await request.json()\n    query = body.get(\"query\", \"\")\n    completion = openai_client.chat.completions.create(\n        model=\"gpt-4o-mini\",\n        messages=[{\"role\": \"user\", \"content\": query}]\n    )\n    return {\"response\": completion.choices[0].message.content}\n\n@app.get(\"/health\")\nasync def health():\n    return {\"status\": \"ok\"}\n\nif __name__ == \"__main__\":\n    import uvicorn\n    uvicorn.run(app, host=\"0.0.0.0\", port=int(os.environ.get(\"PORT\", 3000)))\n```\n\n## Environment Variables\n\n```bash\nNVM_API_KEY=sandbox:your-api-key\nNVM_ENVIRONMENT=sandbox\nNVM_PLAN_ID=your-plan-id\nOPENAI_API_KEY=sk-your-openai-api-key\nPORT=3000\n```\n\n## Tutorial\n\nComplete working example: [github.com/nevermined-io/tutorials/tree/main/http-simple-agent-py](https://github.com/nevermined-io/tutorials/tree/main/http-simple-agent-py)\n\nFile v1.0.10:references/langchain-integration.md\n\n# LangChain & LangGraph Integration\n\nAdd x402 payment protection to LangChain tools and LangGraph ReAct agents. Python uses the `@requires_payment` decorator + helpers from `payments_py.x402.langchain`; TypeScript uses the matching `requiresPayment` wrapper + helpers from `@nevermined-io/payments/langchain` (see [TypeScript](#typescript-nevermined-iopayments) below). The sections below are Python unless noted.\n\n## Installation\n\n```bash\npip install payments-py[langchain] langgraph langchain-openai\n```\n\nThe `[langchain]` extra installs `langchain-core`. `langgraph` and `langchain-openai` are optional — needed only for the LangGraph agent helper.\n\n## Quick Start — protect a tool\n\nDecorator order is `@tool` **outside**, `@requires_payment` **inside**. The tool function **must** accept a `config: RunnableConfig` parameter — that is how the decorator reads the payment token at call time.\n\n```python\nimport os\nfrom dotenv import load_dotenv\nfrom langchain_core.runnables import RunnableConfig\nfrom langchain_core.tools import tool\nfrom payments_py import Payments, PaymentOptions\nfrom payments_py.x402.langchain import requires_payment\n\nload_dotenv()\n\npayments = Payments.get_instance(\n    PaymentOptions(\n        nvm_api_key=os.environ[\"NVM_API_KEY\"],\n        environment=os.environ.get(\"NVM_ENVIRONMENT\", \"sandbox\"),\n    )\n)\n\nPLAN_ID = os.environ[\"NVM_PLAN_ID\"]\n\n@tool\n@requires_payment(payments=payments, plan_id=PLAN_ID, credits=1)\ndef get_market_insight(topic: str, config: RunnableConfig = None) -> str:\n    \"\"\"Return a short market insight. Costs 1 credit per call.\"\"\"\n    return f\"Market insight for '{topic}': demand is up 12% QoQ.\"\n```\n\nThe decorator automatically:\n- Raises `PaymentRequiredError` when no token is in `config[\"configurable\"][\"payment_token\"]`\n- Verifies the x402 token via the Nevermined facilitator\n- Executes the tool function on successful verification\n- Burns credits after successful execution\n\n## Payment Error Flow — discovery-first\n\n`@requires_payment` raises `PaymentRequiredError` with the full `X402PaymentRequired` payload attached. The buyer learns scheme / network / plan_id from the exception and uses them to acquire a token — no upfront configuration needed beyond an API key.\n\n```python\nfrom payments_py.x402.langchain import PaymentRequiredError\nfrom payments_py.x402.types import (\n    CreateDelegationPayload,\n    DelegationConfig,\n    X402TokenOptions,\n)\n\n# Step 1: call the agent without a token to discover requirements\ntry:\n    agent.invoke({\"messages\": [(\"human\", QUERY)]}, config={\"configurable\": {}})\nexcept PaymentRequiredError as err:\n    accept = err.payment_required.accepts[0]\n    # accept.scheme    → \"nvm:erc4337\" or \"nvm:card-delegation\"\n    # accept.network   → CAIP-2 chain or provider name (stripe, braintree, visa)\n    # accept.plan_id   → which plan to acquire a token against\n\n# Step 2: pick a payment method matching the discovered network and create a\n# delegation once (provider + currency required); reuse its delegation_id later.\npm = next(\n    m for m in payments.delegation.list_payment_methods()\n    if m.provider == accept.network\n)\ndelegation = payments.delegation.create_delegation(\n    CreateDelegationPayload(\n        provider=pm.provider,\n        provider_payment_method_id=pm.id,\n        spending_limit_cents=10000,  # $100 cap per delegation\n        duration_secs=3600,          # 1 hour TTL\n        currency=\"usd\",\n    )\n)\n\n# Step 3: acquire a token against the discovered plan by delegation_id\ntoken = payments.x402.get_x402_access_token(\n    accept.plan_id,\n    token_options=X402TokenOptions(\n        scheme=accept.scheme,\n        delegation_config=DelegationConfig(\n            delegation_id=delegation.delegation_id,\n        ),\n    ),\n)[\"accessToken\"]\n\n# Step 4: retry with the token\nresult = agent.invoke(\n    {\"messages\": [(\"human\", QUERY)]},\n    config={\"configurable\": {\"payment_token\": token}},\n)\n```\n\n## LangGraph agent — `create_paid_react_agent`\n\nLangGraph's default `ToolNode` catches `PaymentRequiredError` and stringifies it into a `ToolMessage` for the LLM, **losing the `X402PaymentRequired` payload**. Use `create_paid_react_agent` instead — it builds the ToolNode with `handle_tool_errors=False` so the exception propagates intact to the outer caller.\n\n```python\nfrom langchain_openai import ChatOpenAI\nfrom payments_py.x402.langchain import create_paid_react_agent\n\nagent = create_paid_react_agent(\n    ChatOpenAI(model=\"gpt-4o-mini\", temperature=0),\n    [get_market_insight],\n    prompt=\"You are a market data assistant. Always call get_market_insight.\",\n)\n```\n\nAll `create_react_agent` kwargs (`prompt`, `state_schema`, `checkpointer`, …) are forwarded.\n\n## Reading the settlement receipt — `last_settlement`\n\nAfter a successful agent call, recover the receipt with `last_settlement()`. LangGraph copies `RunnableConfig.configurable` per node, so the SDK's in-place write of `payment_settlement` isn't visible to the outer caller — `last_settlement()` reads from a module-level slot the decorator updates on every settle.\n\n```python\nfrom payments_py.x402.langchain import last_settlement\n\nresult = agent.invoke(\n    {\"messages\": [(\"human\", QUERY)]},\n    config={\"configurable\": {\"payment_token\": token}},\n)\n\nreceipt = last_settlement()\nif receipt:\n    print(f\"credits redeemed:  {receipt.credits_redeemed}\")\n    print(f\"remaining balance: {receipt.remaining_balance}\")\n    print(f\"transaction:       {receipt.transaction}\")\n```\n\n**Single-tenant only.** The slot is process-global — in multi-tenant servers (concurrent settlements), the value reflects whichever invocation settled most recently. Use a callback or observability layer for multi-tenant scenarios.\n\n## Observability with LangSmith — `payments-py[langsmith]`\n\nInstall the optional extra (`pip install \"payments-py[langchain,langsmith]\"`) and set `LANGSMITH_TRACING=true` + `LANGSMITH_API_KEY` (+ `LANGSMITH_ENDPOINT=https://eu.api.smith.langchain.com` for non-US accounts). `@requires_payment` then automatically emits two dedicated child spans nested under the active tool span — `nvm:verify` and `nvm:settlement` — each carrying `nvm.*` metadata for audit and reconciliation. No code changes required.\n\n```text\nLangGraph\n└── tools\n    └── get_market_insight\n        ├── nvm:verify      attrs: nvm.plan_ids, nvm.scheme, nvm.network, nvm.payer, nvm.agent_request_id, nvm.payment_token (abbrev), nvm.verify.duration_ms\n        └── nvm:settlement  attrs: nvm.credits_redeemed, nvm.balance.after, nvm.tx_hash, nvm.payer, nvm.payment_token (abbrev), nvm.settle.duration_ms\n```\n\nThe same `nvm.*` metadata is also attached to the parent tool span. Failed discovery probes (no `payment_token` in config) still produce an `nvm:verify` span with the static attrs, marked failed by the raised `PaymentRequiredError` — so observability survives the first invocation of the discovery-first flow.\n\n**Token redaction.** LangChain auto-captures every key in `config[\"configurable\"]` into the parent tool span's metadata, which child spans inherit. The decorator strips `payment_token` from the parent span before opening any `nvm:*` child, so the full credential never reaches a Nevermined-emitted attribute. The abbreviated `nvm.payment_token` (`<first 16>…<last 4>`) remains for correlation. To cover non-configurable channels (custom callbacks, tool args, etc.) set `LANGSMITH_HIDE_INPUTS=true` for blanket coverage.\n\nObservability failures are silently logged and dropped — the payment flow itself is never interrupted, and `last_settlement()` continues to return the on-chain receipt even if span emission fails.\n\n## Decorator Configuration\n\n### Single plan\n\n```python\n@tool\n@requires_payment(payments=payments, plan_id=\"plan-123\", credits=1)\ndef my_tool(query: str, config: RunnableConfig = None) -> str: ...\n```\n\n### Multiple plans\n\n```python\n@tool\n@requires_payment(\n    payments=payments,\n    plan_ids=[\"plan-basic\", \"plan-premium\"],\n    credits=1,\n)\ndef my_tool(query: str, config: RunnableConfig = None) -> str: ...\n```\n\n### Dynamic credits\n\n```python\n@tool\n@requires_payment(\n    payments=payments,\n    plan_id=PLAN_ID,\n    credits=lambda ctx: max(1, len(ctx[\"result\"]) // 100),\n)\ndef summarize(text: str, config: RunnableConfig = None) -> str:\n    \"\"\"Cost scales with output length.\"\"\"\n    return f\"Summary of: {text}...\"\n```\n\nThe `ctx` dict passed to the credits callable is `{\"args\": <tool kwargs>, \"result\": <tool return>}`. Resolved **after** execution so the result is available.\n\n### With agent ID\n\n```python\n@tool\n@requires_payment(\n    payments=payments,\n    plan_id=PLAN_ID,\n    credits=1,\n    agent_id=os.environ.get(\"NVM_AGENT_ID\"),\n)\ndef my_tool(query: str, config: RunnableConfig = None) -> str: ...\n```\n\n## Credits semantics — fixed vs. range plans\n\nThe `credits` argument is sent to the facilitator as `max_amount`. The amount actually redeemed depends on the plan's server-side credit config:\n\n- **Fixed plans** (where `plan.credits.minAmount == plan.credits.maxAmount`) always burn `plan.credits.maxAmount`. The decorator's `credits=N` is effectively a no-op.\n- **Range plans** clamp the value into `[plan.credits.minAmount, plan.credits.maxAmount]`.\n\nConfigure the plan as fixed if you want predictable per-call cost; the decorator value is then a client-side declaration.\n\n## TypeScript (`@nevermined-io/payments`)\n\nThe TypeScript SDK ships the same primitives under the `@nevermined-io/payments/langchain` sub-path export. The shapes match the Python API one-to-one; only the casing and idioms differ (`requiresPayment` is a higher-order **wrapper** around the tool implementation, not a decorator).\n\n```bash\npnpm add @nevermined-io/payments @langchain/core @langchain/langgraph @langchain/openai\n```\n\n`@langchain/core` is the only LangChain peer the wrapper needs; `@langchain/langgraph` and `@langchain/openai` are optional — required only for `createPaidReactAgent`. `createPaidReactAgent` imports `@langchain/langgraph` lazily, so it is **async** (`await`).\n\n### Protect a tool\n\n```typescript\nimport { tool } from '@langchain/core/tools'\nimport { z } from 'zod'\nimport { Payments } from '@nevermined-io/payments'\nimport { requiresPayment } from '@nevermined-io/payments/langchain'\n\nconst payments = Payments.getInstance({\n  nvmApiKey: process.env.NVM_API_KEY!,\n  environment: process.env.NVM_ENVIRONMENT ?? 'sandbox',\n})\n\nconst PLAN_ID = process.env.NVM_PLAN_ID!\n\nconst getMarketInsight = tool(\n  requiresPayment(\n    (args) => `Market insight for '${args.topic}': demand is up 12% QoQ.`,\n    { payments, planId: PLAN_ID, credits: 1 },\n  ),\n  {\n    name: 'get_market_insight',\n    description: 'Return a short market insight. Costs 1 credit per call.',\n    schema: z.object({ topic: z.string() }),\n  },\n)\n```\n\nThe wrapper extracts the token from `config.configurable.payment_token` (the second arg LangChain threads into the tool impl), verifies via the facilitator, runs the tool, then settles. Missing/invalid token → `PaymentRequiredError` carrying the `X402PaymentRequired` payload.\n\n### LangGraph agent + discovery-first flow\n\n`createPaidReactAgent` builds the underlying `ToolNode` with `handleToolErrors: false` so `PaymentRequiredError` reaches `agent.invoke()`'s caller with its payload intact (the default `ToolNode` would stringify it into a `ToolMessage` and lose the payload).\n\n```typescript\nimport { ChatOpenAI } from '@langchain/openai'\nimport {\n  PaymentRequiredError,\n  createPaidReactAgent,\n  lastSettlement,\n} from '@nevermined-io/payments/langchain'\n\nconst agent = await createPaidReactAgent(\n  new ChatOpenAI({ model: 'gpt-4o-mini', temperature: 0 }),\n  [getMarketInsight],\n  { prompt: 'You are a market data assistant.' },\n)\n\n// 1. Discover by invoking without a token.\nlet accept\ntry {\n  await agent.invoke(\n    { messages: [{ role: 'human', content: QUERY }] },\n    { configurable: {} },\n  )\n} catch (err) {\n  if (!(err instanceof PaymentRequiredError)) throw err\n  accept = err.paymentRequired!.accepts[0] // .scheme / .network / .planId\n}\n\n// 2. Pick a payment method matching the discovered network and create a\n//    delegation once (provider + currency required); reuse its delegationId.\nconst methods = await payments.delegation.listPaymentMethods()\nconst pm = methods.find((m) => m.provider === accept.network)!\nconst delegation = await payments.delegation.createDelegation({\n  provider: pm.provider!,\n  providerPaymentMethodId: pm.id,\n  spendingLimitCents: 10000, // $100 cap per delegation\n  durationSecs: 3600, // 1 hour TTL\n  currency: 'usd',\n})\n\n// 3. Acquire a token against the discovered plan by delegationId.\nconst { accessToken } = await payments.x402.getX402AccessToken(\n  accept.planId,\n  undefined,\n  {\n    scheme: accept.scheme,\n    delegationConfig: { delegationId: delegation.delegationId },\n  },\n)\n\n// 4. Retry with the token, then read the receipt.\nawait agent.invoke(\n  { messages: [{ role: 'human', content: QUERY }] },\n  { configurable: { payment_token: accessToken } },\n)\nconst receipt = lastSettlement()\nif (receipt) {\n  console.log(`credits redeemed:  ${receipt.creditsRedeemed}`)\n  console.log(`remaining balance: ${receipt.remainingBalance}`)\n  console.log(`transaction:       ${receipt.transaction}`)\n}\n```\n\nAll extra `createReactAgent` options (`prompt`, `stateSchema`, `checkpointer`, …) are forwarded. `lastSettlement()` reads from a process-global module slot with the same **single-tenant** caveat as Python: in multi-tenant servers the value reflects whichever invocation settled most recently.\n\n### Dynamic credits\n\n`credits` accepts a static number or a callback `(ctx) => number`, where `ctx` is `{ args, result }` resolved **after** execution.\n\n```typescript\nconst summarize = tool(\n  requiresPayment((args) => `Summary of: ${args.text}...`, {\n    payments,\n    planId: PLAN_ID,\n    credits: (ctx) => Math.max(1, Math.floor(String(ctx.result).length / 100)),\n  }),\n  { name: 'summarize', description: 'Cost scales with output length.', schema: z.object({ text: z.string() }) },\n)\n```\n\nThe fixed-vs-range credits semantics ([above](#credits-semantics--fixed-vs-range-plans)) apply identically — `credits` is sent as `maxAmount`.\n\n**Observability.** Install the optional `langsmith` peer dependency and set `LANGSMITH_TRACING=true`: `requiresPayment` then emits the same `nvm:verify` / `nvm:settlement` spans as the Python SDK, attribute for attribute. The span helpers are also exported from `@nevermined-io/payments/langsmith` for manual use outside LangChain; they no-op when tracing is off or `langsmith` isn't installed.\n\n## Alternative: HTTP middleware\n\nFor serving the agent over HTTP, use `payments_py.x402.fastapi.PaymentMiddleware` instead of the decorator. Tools become plain functions; payment is enforced at the HTTP boundary via the `payment-signature` header.\n\n```python\nfrom fastapi import FastAPI\nfrom payments_py.x402.fastapi import PaymentMiddleware\n\napp = FastAPI()\napp.add_middleware(\n    PaymentMiddleware,\n    payments=payments,\n    routes={\"POST /ask\": {\"plan_id\": PLAN_ID, \"credits\": 1}},\n)\n```\n\nSee [`fastapi-integration.md`](./fastapi-integration.md) for the full FastAPI pattern.\n\n## Environment Variables\n\n```bash\nNVM_API_KEY=sandbox:your-api-key\nNVM_ENVIRONMENT=sandbox             # or 'live'\nNVM_PLAN_ID=your-plan-id\nNVM_AGENT_ID=your-agent-id          # Optional\nOPENAI_API_KEY=sk-your-openai-key   # Or your preferred model provider\n```\n\n## Tutorial\n\nComplete working example: [github.com/nevermined-io/tutorials/tree/main/langchain-paid-agent-py](https://github.com/nevermined-io/tutorials/tree/main/langchain-paid-agent-py)\n\nFile v1.0.10:references/mcp-paywall.md\n\n# MCP Server Paywall\n\nProtect Model Context Protocol (MCP) servers with Nevermined payments. The library handles MCP server creation, OAuth 2.1 endpoints, paywall protection, and credit billing.\n\n## Installation\n\n```bash\nnpm install @nevermined-io/payments zod\n```\n\n## Quick Start — Complete MCP Server\n\n```typescript\nimport { Payments } from \"@nevermined-io/payments\"\nimport { z } from \"zod\"\n\nconst payments = Payments.getInstance({\n  nvmApiKey: process.env.NVM_API_KEY!,\n  environment: \"sandbox\"\n})\n\n// Register tools with built-in paywall\npayments.mcp.registerTool(\n  \"weather.today\",\n  {\n    title: \"Today's Weather\",\n    description: \"Get weather for a city\",\n    inputSchema: z.object({\n      city: z.string().min(2).max(80).describe(\"City name\")\n    })\n  },\n  async (args, extra, context) => {\n    console.log(`Request ID: ${context?.agentRequest?.agentRequestId}`)\n    console.log(`Credits charged: ${context?.credits}`)\n\n    const weather = await fetchWeather(args.city)\n    return {\n      content: [{\n        type: \"text\",\n        text: `Weather in ${args.city}: ${weather.description}, ${weather.temp}°C`\n      }]\n    }\n  },\n  { credits: 5n }\n)\n\n// Start everything (MCP Server + Express + OAuth)\nconst { info, stop } = await payments.mcp.start({\n  port: 3000,\n  planId: process.env.NVM_PLAN_ID!,    // required — the plan every paywalled tool charges against\n  agentId: process.env.NVM_AGENT_ID,   // optional, informational\n  serverName: \"my-weather-server\",\n  version: \"1.0.0\",\n  description: \"Weather MCP server with OAuth authentication\"\n})\n\nconsole.log(`Server running at ${info.baseUrl}/mcp`)\n\nprocess.on(\"SIGINT\", async () => {\n  await stop()\n  process.exit(0)\n})\n```\n\n## What `payments.mcp.start()` Does\n\nThis single call handles:\n1. **Express Server Setup** — creates and configures the Express.js application\n2. **OAuth Endpoints** — auto-generates RFC-compliant discovery endpoints:\n   - `/.well-known/oauth-authorization-server`\n   - `/.well-known/oauth-protected-resource`\n   - `/.well-known/openid-configuration`\n   - `/register` (Dynamic Client Registration — RFC 7591)\n3. **MCP Transport** — HTTP transport endpoints (POST/GET/DELETE `/mcp`)\n4. **Session Management** — SSE streaming and session lifecycle\n5. **CORS & Middleware** — CORS, JSON parsing, HTTP logging\n6. **Graceful Shutdown** — returns a `stop()` function\n\n## Dynamic Credits\n\nCalculate credits based on the handler's result instead of using a fixed value:\n\n```typescript\nimport type { CreditsContext } from \"@nevermined-io/payments\"\n\nconst dynamicCredits = (ctx: CreditsContext): bigint => {\n  const result = ctx.result as { content: Array<{ text: string }> }\n  const text = result.content[0]?.text || \"\"\n  return BigInt(Math.ceil(text.length / 100))\n}\n\npayments.mcp.registerTool(\n  \"weather.today\",\n  config,\n  handler,\n  { credits: dynamicCredits }\n)\n```\n\n- **Fixed credits** (`credits: 5n`): calculated BEFORE handler execution\n- **Dynamic credits** (function): calculated AFTER handler execution, based on `ctx.result`\n\n## Handler Options\n\n| Option | Type | Description |\n|--------|------|-------------|\n| `credits` | `bigint` or `function` | Credits to consume per call |\n| `planId` | `string` | Per-tool plan ID (otherwise the server-level `planId` from `start()` / `configure()`) |\n| `maxAmount` | `bigint` | Max credits to verify during authentication (default: `1n`) |\n| `onRedeemError` | `string` | For non-streaming tools: `'ignore'` (default) returns the in-band payment error when settlement fails; `'propagate'` throws a `-32002` error instead. Either way the tool's content is not returned |\n\n## Response Metadata (`_meta`)\n\nAfter a paywall-protected call settles, the SDK adds two keys to the result's `_meta`: the x402 settlement receipt under `x402/payment-response`, and a Nevermined summary under `nevermined/credits`:\n\n```typescript\n{\n  content: [{ type: 'text', text: 'result' }],\n  _meta: {\n    'x402/payment-response': { success: true, transaction: '0xabc...', network: 'eip155:84532', /* ...full settle receipt */ },\n    'nevermined/credits': {\n      success: true,\n      billingModel: 'credits',\n      txHash: '0xabc...',\n      creditsRedeemed: '5',\n      remainingBalance: '95',\n      planId: 'plan-123',\n      subscriberAddress: '0x123...',\n    },\n  },\n}\n```\n\nFor a non-streaming tool, if settlement fails after the tool ran, the tool's content is **not** returned: the call comes back as an error tool result (`isError: true`, the `PaymentRequired` object in `structuredContent`), so a paid result is never delivered unpaid. A streaming tool (a handler returning an `AsyncIterable`) has already yielded its chunks when settlement runs, so a failure is reported only in the final `_meta` chunk: `nevermined/credits` with `success: false` and an `errorReason`, and no `x402/payment-response`.\n\nFields of `_meta['nevermined/credits']`:\n\n| Field | Type | Description |\n|-------|------|-------------|\n| `success` | `boolean` | Whether settlement succeeded (`true` for calls that settle nothing) |\n| `billingModel` | `string` | `credits` or `pay-as-you-go`. **Read this before either credit field.** Absent on a deployment predating it; treat that as `credits`. |\n| `txHash` | `string` | Settlement transaction reference (when present) |\n| `creditsRedeemed` | `string` | Number of credits burned — **always `'0'` on a pay-as-you-go plan, including a successful charge**. Omitted when the settle reported no figure |\n| `remainingBalance` | `string` | Credits remaining after redemption (also always `'0'` on pay-as-you-go) |\n| `orderTx` | `string` | Charge reference on pay-as-you-go plans (when present) |\n| `planId` | `string` | Plan used for the operation |\n| `subscriberAddress` | `string` | Subscriber's wallet address |\n| `errorReason` | `string` | Streaming tools only, on a failed settlement: why it failed |\n\n## Client Usage\n\n### Get Access Token\n\n```typescript\nconst delegation = await paymentsClient.delegation.createDelegation({\n  provider: 'erc4337', spendingLimitCents: 100, durationSecs: 3600, currency: 'usdc'\n})\nconst { accessToken } = await paymentsClient.x402.getX402AccessToken(planId, agentId, {\n  delegationConfig: { delegationId: delegation.delegationId }\n})\n```\n\n### Connect with MCP Client\n\n```typescript\nimport { Client } from \"@modelcontextprotocol/sdk/client\"\nimport { StreamableHTTPClientTransport } from \"@modelcontextprotocol/sdk/client/streamableHttp\"\nimport { decodeAccessToken } from \"@nevermined-io/payments\"\n\n// Nevermined MCP servers do not read the `payment-signature` header. The `/mcp`\n// endpoint requires `Authorization: Bearer <accessToken>`; the paywall prefers the\n// in-band `_meta[\"x402/payment\"]` payload (below) when present.\nconst transport = new StreamableHTTPClientTransport(\n  new URL(\"http://localhost:3000/mcp\"),\n  {\n    requestInit: {\n      headers: { Authorization: `Bearer ${accessToken}` }\n    }\n  }\n)\n\nconst client = new Client({ name: \"my-client\" })\nawait client.connect(transport)\n\nconst result = await client.callTool({\n  name: \"weather.today\",\n  arguments: { city: \"Madrid\" },\n  _meta: { \"x402/payment\": decodeAccessToken(accessToken) },\n})\n```\n\n### Claude Desktop Configuration\n\nAdd to `~/Library/Application Support/Claude/claude_desktop_config.json` (macOS):\n\n```json\n{\n  \"mcpServers\": {\n    \"weather\": {\n      \"url\": \"http://localhost:3000/mcp\",\n      \"type\": \"http\"\n    }\n  }\n}\n```\n\nOAuth authentication is handled automatically by the server.\n\n## Advanced: Low-Level APIs\n\n`withPaywall` and `attach` need a resolvable plan ID when a handler is registered — configure it server-wide first or pass `planId` per handler; otherwise registration throws `Server misconfiguration: missing planId`.\n\n### `withPaywall` for Custom Servers\n\n```typescript\npayments.mcp.configure({ planId: process.env.NVM_PLAN_ID!, serverName: \"my-server\" })\n\nconst protectedHandler = payments.mcp.withPaywall(\n  myHandler,\n  {\n    kind: \"tool\",\n    name: \"my.tool\",\n    credits: 5n\n  }\n)\n```\n\n### `attach` for Declarative Registration\n\n```typescript\nconst server = new McpServer({ name: \"my-server\", version: \"1.0.0\" })\nconst registrar = payments.mcp.attach(server)\n\nregistrar.registerTool(\n  \"weather.today\",\n  config,\n  handler,\n  { credits: 1n }\n)\n```\n\n## MCP Error Codes\n\nFor **tools**, Payment Required (no token, invalid token, insufficient credits, or settlement failed after execution) is not a JSON-RPC error: it comes back in band as a tool result with `isError: true` and the `PaymentRequired` object in `structuredContent` (x402 v2 MCP transport). Resources and prompts have no tool-result channel, so there it surfaces as a JSON-RPC error.\n\n| Error Code | Description |\n|---|---|\n| `-32003` | Payment Required — resources and prompts only (see above for tools); the MCP SDK may forward only the message, not the code |\n| `-32002` | Misconfiguration — server setup error |\n| `-32603` | Internal Error — handler execution failed |\n\n## Logical MCP URLs\n\nNevermined identifies protected methods by logical URL:\n`mcp://<serverName>/<typeName>/<methodName>`\n\n- `mcp://weather-mcp/tools/weather.today`\n- `mcp://weather-mcp/resources/weather.ensureCity`\n- `mcp://weather-mcp/meta/initialize`\n\nFor dynamic URIs, use placeholders: `mcp://weather-mcp/resources/weather.today?city={city}`\n\n## Environment Variables\n\n```bash\nNVM_API_KEY=sandbox:your-api-key\nNVM_ENVIRONMENT=sandbox\nNVM_PLAN_ID=your-plan-id\nNVM_AGENT_ID=your-agent-id          # Optional\n```\n\n## Tutorial\n\nProduction-ready example: [github.com/nevermined-io/tutorials/tree/main/mcp-examples/weather-mcp](https://github.com/nevermined-io/tutorials/tree/main/mcp-examples/weather-mcp)\n\nFile v1.0.10:references/payment-plans.md\n\n# Payment Plans\n\nHow to register agents and create payment plans programmatically using the Nevermined SDK.\n\n## Plan Types\n\n| Type | Description | Use Case |\n|---|---|---|\n| **Credits-based** | Prepaid credits, deducted per request | Per-request API billing |\n| **Time-based** | Access for a fixed duration | Monthly/yearly subscriptions |\n| **Pay-as-you-go** | Settle in USDC per request | On-demand, no prepaid balance |\n| **Trial** | Free limited access, one-time claim | Let users try your service |\n| **Hybrid** | Credits with time expiry | e.g., 1000 credits valid for 30 days |\n\n## Register Agent + Plan (Combined)\n\n### TypeScript\n\n```typescript\nimport { Payments } from '@nevermined-io/payments'\n\nconst USDC_ADDRESS = '0x036CbD53842c5426634e7929541eC2318f3dCF7e'\n\nasync function main() {\n  const payments = Payments.getInstance({\n    nvmApiKey: process.env.NVM_API_KEY!,\n    environment: 'sandbox'\n  })\n\n  const { agentId, planId } = await payments.agents.registerAgentAndPlan(\n    // Agent metadata\n    {\n      name: 'My AI Assistant',\n      description: 'A paid AI service',\n      tags: ['ai', 'payments'],\n      dateCreated: new Date()\n    },\n    // Agent interface — endpoints and agentDefinitionUrl are both optional.\n    // Provide endpoints only when you want the Nevermined platform to enforce\n    // route-level Additional Security on top of your library middleware.\n    {\n      endpoints: [{ POST: 'https://your-api.com/query' }]\n    },\n    // Plan metadata\n    {\n      name: 'Starter Plan',\n      description: '100 requests for $10',\n      dateCreated: new Date()\n    },\n    // Price: 10 USDC (6 decimals)\n    payments.plans.getERC20PriceConfig(\n      10_000_000n,\n      USDC_ADDRESS,\n      process.env.BUILDER_ADDRESS!\n    ),\n    // Credits: 100 requests, 1 credit each\n    payments.plans.getFixedCreditsConfig(100n, 1n)\n  )\n\n  console.log(`Agent ID: ${agentId}`)\n  console.log(`Plan ID: ${planId}`)\n}\n\nmain().catch(console.error)\n```\n\n### Python\n\n```python\nimport os\nfrom payments_py import Payments, PaymentOptions\nfrom payments_py.plans import get_erc20_price_config, get_fixed_credits_config\n\nUSDC_ADDRESS = '0x036CbD53842c5426634e7929541eC2318f3dCF7e'\n\ndef main():\n    payments = Payments.get_instance(\n        PaymentOptions(\n            nvm_api_key=os.environ['NVM_API_KEY'],\n            environment='sandbox'\n        )\n    )\n\n    result = payments.agents.register_agent_and_plan(\n        agent_metadata={\n            'name': 'My AI Assistant',\n            'description': 'A paid AI service',\n            'tags': ['ai', 'payments']\n        },\n        # agent_api is required, but its `endpoints` and `agent_definition_url`\n        # fields are optional: omit them for an open agent (no platform-side\n        # route enforcement); include `endpoints` for Additional Security.\n        agent_api={\n            'endpoints': [{'POST': 'https://your-api.com/query'}]\n        },\n        plan_metadata={\n            'name': 'Starter Plan',\n            'description': '100 requests for $10'\n        },\n        price_config=get_erc20_price_config(\n            10_000_000,\n            USDC_ADDRESS,\n            os.environ['BUILDER_ADDRESS']\n        ),\n        credits_config=get_fixed_credits_config(100, 1),\n        access_limit='credits'\n    )\n\n    print(f\"Agent ID: {result['agentId']}\")\n    print(f\"Plan ID: {result['planId']}\")\n\nif __name__ == '__main__':\n    main()\n```\n\n## Using the Nevermined App (No-Code)\n\nYou can also register agents and create plans through the [Nevermined App](https://nevermined.app) UI:\n\n1. Go to [nevermined.app](https://nevermined.app) and sign in\n2. Click \"My agents\" to register a new agent\n3. Fill in metadata: name, description, tags\n4. Register API endpoints (HTTP URLs for APIs, logical MCP URLs for MCP servers)\n5. Create a payment plan: set pricing, credits, and duration\n6. Link the plan to your agent and publish\n7. Copy the `agentId` and `planId` for your integration\n\n## Plan Configuration Details\n\n### Credits Config\n\n```typescript\n// TypeScript\npayments.plans.getFixedCreditsConfig(\n  100n,  // Total credits in the plan\n  1n     // Credits consumed per request\n)\n```\n\n```python\n# Python — both call sites work\npayments.plans.get_fixed_credits_config(100, 1)\n# or:\nfrom payments_py.plans import get_fixed_credits_config\nget_fixed_credits_config(\n    100,  # Total credits in the plan\n    1     # Credits consumed per request\n)\n```\n\n### Variable Credits (Dynamic Pricing)\n\nWhen using dynamic credits (a function instead of fixed value), configure the plan with a price range:\n\n- Enable \"Want to set a price range per request?\" in the App\n- Set min and max price per request\n- If your code calculates credits outside the range, it gets capped to the configured limits\n\n### Price Config\n\n```typescript\n// ERC-20 token payment (USDC on Base Sepolia)\npayments.plans.getERC20PriceConfig(\n  10_000_000n,           // Price in token smallest unit (10 USDC = 10 * 10^6)\n  USDC_ADDRESS,          // Token contract address\n  process.env.BUILDER_ADDRESS!  // Recipient wallet\n)\n\n// EURC stablecoin (defaults to Base Mainnet EURC if address omitted)\npayments.plans.getEURCPriceConfig(10_000_000n, BUILDER_ADDRESS)\n\n// Native token (e.g. ETH on Base)\npayments.plans.getNativeTokenPriceConfig(10_000_000n, BUILDER_ADDRESS)\n\n// Free plan (used for trials)\npayments.plans.getFreePriceConfig()\n```\n\n## Fiat Plans (Stripe / Braintree / Visa)\n\nFiat plans use the `nvm:card-delegation` x402 scheme — subscribers enroll a card via Stripe, Braintree, or the Visa Trusted Agent Protocol, and per-request charges are settled by the configured provider. The active provider per plan is set by the seller's `fiatPaymentProvider` metadata (`'stripe'` | `'braintree'` | `'visa'`).\n\n> **Fiat amount units.** `getFiatPriceConfig` takes the amount in **6-decimal units** (the USDC convention used across the protocol) — `10_000_000n` = $10.00 — **NOT cents**. The server-side minimum is **$1.00** (`1_000_000n`); anything smaller is rejected with `BCK.PROTOCOL.0047`. (This is distinct from `spendingLimitCents` on a *delegation*, which really is in cents.)\n\n```typescript\n// TypeScript — $10.00 fiat, paid into the builder's wallet/account\nconst fiatPriceConfig = payments.plans.getFiatPriceConfig(\n  10_000_000n,        // $10.00 — 6-decimal units (the USDC convention), NOT cents\n  process.env.BUILDER_ADDRESS!,\n  'USD'               // any ISO 4217 code Stripe accepts (USD, EUR, ...)\n)\n\nconst { planId } = await payments.plans.registerPlan(\n  { name: 'Fiat Starter', description: '100 requests for $10', dateCreated: new Date() },\n  fiatPriceConfig,\n  payments.plans.getFixedCreditsConfig(100n, 1n),\n)\n```\n\n```python\n# Python\nfiat_price_config = payments.plans.get_fiat_price_config(\n    10_000_000,  # $10.00 — 6-decimal units, NOT cents\n    os.environ[\"BUILDER_ADDRESS\"],\n    \"USD\",\n)\n```\n\nWhen subscribers fetch an x402 token for a fiat plan, the supported flow is **create-first**: create the delegation, then reuse it by `delegationId`.\n\n- **Create the delegation** (`provider` + `currency` required), e.g. for Stripe / Braintree:\n  ```ts\n  const delegation = await payments.delegation.createDelegation({\n    provider: 'stripe', providerPaymentMethodId: 'pm_…', spendingLimitCents: 1000, durationSecs: 86400, currency: 'usd'\n  })\n  ```\n- **Reuse it by `delegationId`** (works for all networks, including Visa):\n  ```ts\n  delegationConfig: { delegationId: delegation.delegationId }\n  ```\n\nThe SDK auto-resolves `nvm:card-delegation` from the plan's `priceConfig`. Passing the creation fields inline in `delegationConfig` (a `delegationConfig` without `delegationId`) is **deprecated** and emits a runtime deprecation warning — create the delegation first. For **Visa** plans, only the reuse path works — Visa delegations must be created in the Nevermined webapp (browser-only WebAuthn ceremony) and reused from the SDK by ID. Attempting `create_delegation(provider='visa', ...)` from the SDK is rejected with `BCK.VISA.0014` because the required `consumerPrompt` and `assuranceData` blobs can only be produced in-browser.\n\n## Pay-As-You-Go Plans\n\nPAYG plans grant exactly **one credit per purchase** — every call requires the subscriber to re-order the plan. Use the dedicated helpers:\n\n```typescript\n// TypeScript\nconst paygPriceConfig = await payments.plans.getPayAsYouGoPriceConfig(\n  1_000_000n,                    // amount per call (1 USDC, 6 decimals)\n  process.env.BUILDER_ADDRESS!,\n  USDC_ADDRESS,                  // optional — defaults to native token\n)\nconst paygCreditsConfig = payments.plans.getPayAsYouGoCreditsConfig()\n\nconst { planId } = await payments.plans.registerPlan(\n  { name: 'PAYG', description: '$1 per call', dateCreated: new Date() },\n  paygPriceConfig,\n  paygCreditsConfig,\n)\n```\n\n```python\n# Python\npayg_price_config = payments.plans.get_pay_as_you_go_price_config(\n    1_000_000, os.environ[\"BUILDER_ADDRESS\"], USDC_ADDRESS\n)\npayg_credits_config = payments.plans.get_pay_as_you_go_credits_config()\n```\n\n## Example Plans\n\n| Plan | Price | Credits | Duration | Use Case |\n|---|---|---|---|---|\n| Starter | $10 USDC | 100 | None | Small-scale API testing |\n| Pro | $49 USDC | 1000 | 30 days | Production usage |\n| Unlimited | $99 USDC | Unlimited | 30 days | High-volume access |\n| Trial | Free | 10 | 7 days | Try before you buy |\n| Fiat Starter | $10.00 (Stripe) | 100 | None | Card-paying subscribers |\n| PAYG | $1 USDC / call | 1 per purchase | None | Pay-per-call without prepaid balance |\n\nFile v1.0.10:references/seller-operations.md\n\n# Seller Operations — status & revenue\n\nHow an agent (or its operator) checks the **performance of the plans and agents it sells**: revenue, recurring revenue, usage, customers, and the underlying plan/agent inventory. Companion to **Track A · A7** in `SKILL.md`.\n\n> Verified against the live sandbox API. Send `Authorization: Bearer $NVM_API_KEY` on every call. The `analytics/*` endpoints are served by the platform but are **not** discoverable in the live `docs-json` (it lists only `agentic-instructions.md` / `llms.txt` under `organizations`), so use the paths below directly.\n\n## Two layers\n\n1. **Organization analytics** — aggregated revenue/MRR/usage/customers. **Requires an active Premium organization tier.** Needs your `orgId` (discover it from `.orgId` on your plan/agent records — see §2). Failure modes: `403 BCK.ORGANIZATIONS.0022` (not Premium), `403 BCK.AUTH.0004` (not an admin of that org), or a **silent `200`-of-zeros** for a malformed/placeholder `orgId`.\n2. **Protocol building blocks** — list your plans/agents and read individual balances. **Any tier**, no `orgId` needed (user-scoped to your API key).\n\n---\n\n## 1. Organization analytics (Premium)\n\nSet the analytics base once — the `curl`s below reuse `$B` in the same shell session. Date params are ISO-8601; `from` inclusive, `to` exclusive.\n\n```bash\nB=\"https://api.sandbox.nevermined.app/api/v1/organizations/<ORG_ID>/analytics\"\n```\n\n### Revenue per agent\n\n```bash\ncurl -s -H \"Authorization: Bearer $NVM_API_KEY\" \\\n  \"$B/revenue?from=2026-03-20T00:00:00Z&to=2026-06-18T00:00:00Z\"\n```\n```json\n{\n  \"items\": [\n    { \"agentId\": \"did:nv:...\", \"agentName\": \"Weather Agent\", \"totalRevenue\": \"125000\", \"transactionCount\": 412 }\n  ],\n  \"totalRevenue\": \"125000\"\n}\n```\n`totalRevenue` is a stringified integer in 6-decimal token units (divide by 1,000,000 for USD). Rows are keyed by `agentId`/`agentName` but are actually grouped **by plan**.\n\n### Monthly recurring revenue + active subscriptions\n\n```bash\ncurl -s -H \"Authorization: Bearer $NVM_API_KEY\" \"$B/mrr?asOf=2026-06-01T00:00:00Z\"\n# → { \"mrr\": \"48000\", \"activeSubscriptions\": 37 }\n```\n`asOf` defaults to now.\n\n### Usage (credits burned per plan)\n\n```bash\ncurl -s -H \"Authorization: Bearer $NVM_API_KEY\" \"$B/usage?from=...&to=...&limit=50\"\n# → { \"items\": [ { \"planId\": \"...\", \"planName\": \"Starter\", \"creditsBurned\": \"9120\", \"uniqueUsers\": 64 } ] }\n```\n\n### Top customers\n\n```bash\ncurl -s -H \"Authorization: Bearer $NVM_API_KEY\" \"$B/customers?limit=20\"\n# → { \"items\": [ { \"customerId\": \"...\", \"userId\": \"...\", \"totalSpent\": \"32000\",\n#                  \"firstSeenAt\": \"2026-02-...\", \"lastActiveAt\": \"2026-06-...\" } ],\n#      \"totalCustomers\": 128 }\n```\n\n> **Finding your `orgId`:** discover it from your own records — every item in `GET /protocol/plans` and `/protocol/agents` (§2) carries `.orgId` + `.organizationName`; take the most common non-null `.orgId` (it's the `org-...` id, also used in `…/organizations/<orgId>/agentic-instructions.md`). Only call analytics with an id matching `^org-[0-9a-f-]+$` — a malformed one returns a deceptive `200`-of-zeros. If you don't operate under an org, use the building blocks below.\n\n---\n\n## 2. Protocol building blocks (any tier)\n\nThese are user-scoped to your API key — no `orgId` and no Premium needed.\n\n```bash\n# Your published plans (paginated)\ncurl -s -H \"Authorization: Bearer $NVM_API_KEY\" \\\n  \"https://api.sandbox.nevermined.app/api/v1/protocol/plans?page=1&offset=20\"\n# → { total, page, offset, plans: [ <full plan record> ] }\n#   Each item is the entity, not a flat summary: name at metadata.main.name,\n#   price/type in registry/metadata, id at .id (no flat planName/pricePerCredit/planType here —\n#   that flat shape is only on the balance endpoint).\n\n# Your published agents\ncurl -s -H \"Authorization: Bearer $NVM_API_KEY\" \\\n  \"https://api.sandbox.nevermined.app/api/v1/protocol/agents?page=1&offset=20\"\n# → { total, page, offset, agents: [ <full agent record> ] }\n#   Each item is the entity: name at metadata.main.name, id at .id (no flat agentName/description).\n\n# Plans attached to one agent\ncurl -s -H \"Authorization: Bearer $NVM_API_KEY\" \\\n  \"https://api.sandbox.nevermined.app/api/v1/protocol/agents/<AGENT_ID>/plans\"\n\n# Credits a specific holder has on one of your plans\ncurl -s -H \"Au\n\nArchive v1.0.9: 15 files, 60378 bytes\n\nFiles: references/a2a-integration.md (7506b), references/autonomous-operations.md (15060b), references/client-integration.md (13709b), references/customer-onboarding.md (4056b), references/express-integration.md (4413b), references/fastapi-integration.md (7511b), references/langchain-integration.md (15583b), references/mcp-paywall.md (7476b), references/payment-plans.md (9049b), references/seller-operations.md (5653b), references/strands-integration.md (6770b), references/x402-protocol.md (6640b), skill-card.md (3334b), SKILL.md (52046b), _meta.json (129b)\n\nArchive v1.0.8: 15 files, 59135 bytes\n\nFiles: references/a2a-integration.md (7506b), references/autonomous-operations.md (13979b), references/client-integration.md (12752b), references/customer-onboarding.md (4056b), references/express-integration.md (4408b), references/fastapi-integration.md (7511b), references/langchain-integration.md (15583b), references/mcp-paywall.md (7149b), references/payment-plans.md (9049b), references/seller-operations.md (5653b), references/strands-integration.md (6770b), references/x402-protocol.md (6640b), skill-card.md (3310b), SKILL.md (51168b), _meta.json (129b)\n\nArchive v1.0.7: 15 files, 58884 bytes\n\nFiles: references/a2a-integration.md (7506b), references/autonomous-operations.md (13519b), references/client-integration.md (12752b), references/customer-onboarding.md (4056b), references/express-integration.md (4408b), references/fastapi-integration.md (7511b), references/langchain-integration.md (15583b), references/mcp-paywall.md (7149b), references/payment-plans.md (9049b), references/seller-operations.md (5653b), references/strands-integration.md (6770b), references/x402-protocol.md (6640b), skill-card.md (3412b), SKILL.md (51168b), _meta.json (129b)\n\nArchive v1.0.6: 15 files, 58924 bytes\n\nFiles: references/a2a-integration.md (7506b), references/autonomous-operations.md (13519b), references/client-integration.md (12752b), references/customer-onboarding.md (4056b), references/express-integration.md (4408b), references/fastapi-integration.md (7511b), references/langchain-integration.md (15583b), references/mcp-paywall.md (7149b), references/payment-plans.md (9049b), references/seller-operations.md (5653b), references/strands-integration.md (6770b), references/x402-protocol.md (6640b), skill-card.md (3596b), SKILL.md (51169b), _meta.json (129b)\n\nArchive v1.0.5: 15 files, 58881 bytes\n\nFiles: references/a2a-integration.md (7506b), references/autonomous-operations.md (13519b), references/client-integration.md (12752b), references/customer-onboarding.md (4056b), references/express-integration.md (4408b), references/fastapi-integration.md (7511b), references/langchain-integration.md (15583b), references/mcp-paywall.md (7149b), references/payment-plans.md (9049b), references/seller-operations.md (5653b), references/strands-integration.md (6770b), references/x402-protocol.md (6640b), skill-card.md (3460b), SKILL.md (51185b), _meta.json (129b)\n\nArchive v1.0.4: 15 files, 58972 bytes\n\nFiles: references/a2a-integration.md (7506b), references/autonomous-operations.md (13519b), references/client-integration.md (12752b), references/customer-onboarding.md (4056b), references/express-integration.md (4408b), references/fastapi-integration.md (7511b), references/langchain-integration.md (15583b), references/mcp-paywall.md (7149b), references/payment-plans.md (9049b), references/seller-operations.md (5653b), references/strands-integration.md (6770b), references/x402-protocol.md (6640b), skill-card.md (3745b), SKILL.md (51195b), _meta.json (129b)\n\nArchive v1.0.3: 14 files, 56555 bytes\n\nFiles: references/a2a-integration.md (7506b), references/autonomous-operations.md (13519b), references/client-integration.md (12752b), references/express-integration.md (4408b), references/fastapi-integration.md (7511b), references/langchain-integration.md (15583b), references/mcp-paywall.md (7149b), references/payment-plans.md (9049b), references/seller-operations.md (5653b), references/strands-integration.md (6770b), references/x402-protocol.md (6640b), skill-card.md (4148b), SKILL.md (49837b), _meta.json (129b)\n\nArchive v1.0.2: 14 files, 56139 bytes\n\nFiles: references/a2a-integration.md (7506b), references/autonomous-operations.md (13519b), references/client-integration.md (12752b), references/express-integration.md (4408b), references/fastapi-integration.md (7511b), references/langchain-integration.md (15583b), references/mcp-paywall.md (7149b), references/payment-plans.md (9049b), references/seller-operations.md (5653b), references/strands-integration.md (6770b), references/x402-protocol.md (6640b), skill-card.md (3094b), SKILL.md (49925b), _meta.json (129b)\n\nArchive v1.0.1: 14 files, 56209 bytes\n\nFiles: references/a2a-integration.md (7506b), references/autonomous-operations.md (13519b), references/client-integration.md (12752b), references/express-integration.md (4408b), references/fastapi-integration.md (7511b), references/langchain-integration.md (15583b), references/mcp-paywall.md (7149b), references/payment-plans.md (9049b), references/seller-operations.md (5653b), references/strands-integration.md (6770b), references/x402-protocol.md (6640b), skill-card.md (3353b), SKILL.md (49876b), _meta.json (129b)","readmeExcerpt":"Skill: Nevermined Payments Owner: nevermined-io Summary: Use when an AI agent must operate on Nevermined autonomously — purchase a payment plan via the x402 protocol (crypto or card), enroll a card and create a spending delegation, obtain a Nevermined API key, register a payment plan or AI agent, or check its credits (as a buyer) or revenue (as a seller) — and when adding x402 payment protection to a TypeScript or Py","codeSnippets":[],"executableExamples":[{"language":"text","snippet":"https://nevermined.app/auth/cli?callback_url=http://127.0.0.1:<port>/callback"},{"language":"bash","snippet":"curl -H \"Authorization: Bearer $NVM_API_KEY\" \\"},{"language":"bash","snippet":"curl -H \"Authorization: Bearer $NVM_API_KEY\" \\\n  https://api.sandbox.nevermined.app/api/v1/payment-methods\n# → [ { id, type, brand, last4, provider, status, ... } ]"},{"language":"bash","snippet":"curl -X POST -H \"Authorization: Bearer $NVM_API_KEY\" -H \"Content-Type: application/json\" \\\n  -d '{\"returnUrl\":\"http://127.0.0.1:<port>/callback\"}' \\"},{"language":"bash","snippet":"# 1. Mint an embedded session (host a 127.0.0.1 callback first)\ncurl -X POST -H \"Authorization: Bearer $NVM_API_KEY\" -H \"Content-Type: application/json\" \\\n  -d '{\"returnUrl\":\"http://127.0.0.1:<port>/callback\"}' \\\n  https://api.sandbox.nevermined.app/api/v1/embed/session\n# → { \"sessionToken\": \"...\", \"userId\": \"...\", \"userWallet\": \"0x...\", \"expiresAt\": \"...\" }"},{"language":"text","snippet":"https://embed.nevermined.app/cards/setup?sessionToken=<sessionToken>&returnUrl=http://127.0.0.1:<port>/callback&state=<random>&provider=stripe"}],"parameters":null,"dependencies":[],"permissions":[],"extractedFiles":[{"path":"SKILL.md","content":"---\nname: nevermined-payments\nversion: \"0.5.2\"\nlastUpdated: \"2026-09-25\"\ndescription: >\n  Use when an AI agent must operate on Nevermined autonomously — purchase a payment\n  plan via the x402 protocol (crypto or card), enroll a card and create a spending\n  delegation, obtain a Nevermined API key, register a payment plan or AI agent, or\n  check its credits (as a buyer) or revenue (as a seller) — and when adding x402\n  payment protection to a TypeScript or Python agent (Express, FastAPI, MCP, Google\n  A2A, Strands, LangChain / LangGraph). Covers the @nevermined-io/payments and payments-py SDKs and the\n  Nevermined REST API.\nmetadata:\n  openclaw:\n    primaryEnv: NVM_API_KEY\n    requires:\n      env:\n        - NVM_API_KEY\n    envVars:\n      - name: NVM_API_KEY\n        required: true\n        description: >\n          Nevermined API key used by the SDK, REST API, and CLI. Format\n          `sandbox:...` for the sandbox environment, `live:...` for production.\n          Issued from https://nevermined.app under API Keys.\n---\n\n# Nevermined Payments Integration\n\n> **Skill version**: 0.5.2 | **Last updated**: 2026-09-25 | **Canonical source (always latest):** https://github.com/nevermined-io/docs/tree/main/skills/nevermined-payments\n>\n> **Use the latest version.** This skill changes often. If you have an installed or cached copy, compare its **Last updated** date with the canonical source above and refresh it if older — an out-of-date copy can be missing whole flows. Unless a specific version is requested, work from the latest.\n>\n> Verified against the live sandbox API (`https://api.sandbox.nevermined.app/api/v1/rest/docs-json`); the cited SDK calls were checked against `@nevermined-io/payments@1.13.0` and `payments-py@1.18.0` — install the latest release of each.\n\n## Overview\n\nNevermined provides financial rails for AI agents — real-time monetization, access control, and payments. This skill covers **two modes**, and most tasks fall cleanly into one:\n\n| Mode | You are… | Lead interface | Use when the goal is… |\n|---|---|---|---|\n| **🅐 Operate as an autonomous agent** | an agent **acting on its own behalf** at runtime | **REST** (works with no SDK install) | buy a plan, enroll a card + delegation, get an API key, register a plan/agent, check credits (buyer) or revenue (seller) |\n| **🅑 Add payments to your code** | a developer **wiring payments into an agent** so it can **receive** payments | **SDK** (TypeScript / Python) | protect Express/FastAPI/MCP/A2A/Strands endpoints behind a plan |\n\nIf you are an autonomous agent that needs to **pay, enroll, register, or report**, start at **Track A — Operate as an autonomous agent**. If you are building a service that needs to **charge** callers, jump to **Track B — Add payments to your code**.\n\n### How payments work (x402 in one minute)\n\nNevermined uses the **x402 protocol** (HTTP `402 Payment Required`). A buyer acquires an **access token** authorizing a spend, then **settles** it — which charges the payment method, "},{"path":"_meta.json","content":"{\n  \"ownerId\": \"kn7bk8z6x7ytxvdb48j34j2ahh812m3p\",\n  \"slug\": \"nevermined\",\n  \"version\": \"1.0.10\",\n  \"publishedAt\": 1790357689120\n}"},{"path":"references/a2a-integration.md","content":"# Google A2A Integration\n\nIntegrate Nevermined payments with [Google A2A (Agent-to-Agent)](https://a2a-protocol.org/) to enable multi-agent systems to authorize and charge per request between agents.\n\n> 🔐 **Trust & transport.** A2A flows ship payment tokens (`payment-signature`) between agents — they are bearer credentials. Always: (1) serve agents over HTTPS, (2) validate the peer Agent Card and base URL before sending tokens, (3) restrict CORS to known agent origins, (4) issue short-lived, narrowly scoped **delegations** (`createDelegation` with tight `spendingLimitCents` + `durationSecs`), then request tokens by their `delegationId`, and (5) treat push-notification webhook URLs as untrusted until verified.\n\n## Features\n\n- **Agent Card with payment extension**: served at `/.well-known/agent-card.json` (legacy alias `/.well-known/agent.json`)\n- **In-band payment (x402 v2 A2A transport)**: the client carries the x402 payload in the JSON-RPC message metadata; the `payment-signature` HTTP header is still accepted as a deprecated fallback\n- **Credits Validation**: verify sufficient credits before executing a task\n- **Credits Burning/Redemption**: burn credits specified in `metadata.creditsUsed` after execution\n- **Streaming**: supports `message/stream` and `tasks/resubscribe`\n- **Push Notifications**: standard A2A push notification flow\n- **Async Task Handling**: intermediate and final state events, compatible with polling and streaming\n\n## Installation\n\n### TypeScript\n\n```bash\nnpm install @nevermined-io/payments\n```\n\n### Python\n\n```bash\npip install payments-py\n```\n\n## A2A Server\n\n### Build the Payment Agent Card\n\nAdd a Nevermined payment extension to your A2A agent card to advertise that your agent charges for requests.\n\n#### TypeScript\n\n```typescript\nimport { Payments } from \"@nevermined-io/payments\"\n\nconst payments = Payments.getInstance({\n  nvmApiKey: process.env.NVM_API_KEY!,\n  environment: 'sandbox',\n})\n\nconst baseAgentCard = {\n  name: 'My A2A Server',\n  description: 'A2A agent that requires payment',\n  capabilities: {\n    streaming: true,\n    pushNotifications: true,\n    stateTransitionHistory: true,\n  },\n  defaultInputModes: ['text'],\n  defaultOutputModes: ['text'],\n  skills: [],\n  url: 'http://localhost:3005/a2a/',\n  version: '1.0.0',\n}\n\n// buildPaymentAgentCard is static on the Payments class (not on the `payments` instance)\nconst agentCard = Payments.a2a.buildPaymentAgentCard(baseAgentCard, {\n  paymentType: \"dynamic\",\n  credits: 1,\n  planId: process.env.NVM_PLAN_ID!,\n  agentId: process.env.NVM_AGENT_ID!,\n})\n```\n\n#### Python\n\n```python\nfrom payments_py import Payments, PaymentOptions\nfrom payments_py.a2a.agent_card import build_payment_agent_card\n\npayments = Payments.get_instance(\n    PaymentOptions(nvm_api_key=os.environ[\"NVM_API_KEY\"], environment=\"sandbox\")\n)\n\nbase_agent_card = {\n    \"name\": \"My A2A Agent\",\n    \"description\": \"A2A agent that requires payment\",\n    \"capabilities\": {\n        \"streaming\": True,\n        \"pushNotifications\""},{"path":"references/autonomous-operations.md","content":"# Autonomous Agent Operations (REST runbook)\n\nHow an AI agent operates on Nevermined **on its own behalf** using the REST API — get an API key, enroll a card, create a delegation, purchase plans via x402, and check status. Every call here is plain HTTPS; no SDK install is required. This is the heavy-detail companion to **Track A** in `SKILL.md`.\n\n> All bodies and response shapes below are verified against the live sandbox OpenAPI (`https://api.sandbox.nevermined.app/api/v1/rest/docs-json`). Send `Authorization: Bearer $NVM_API_KEY` on every call unless noted.\n>\n> Also send `Nevermined-Version: <MAJOR.MINOR>` on every call to pin the wire shape across platform releases — discover the supported range with `GET /api/v1/meta/versions` and default to its `current`. Never silently change a key's stored pin.\n\n## Environments\n\n| Environment | API base URL | App | Card enrollment UI | Crypto network | Key prefix |\n|---|---|---|---|---|---|\n| `sandbox` | `https://api.sandbox.nevermined.app` | `https://nevermined.app` | `https://embed.nevermined.app` | `eip155:84532` (Base Sepolia) | `sandbox:` |\n| `live` | `https://api.live.nevermined.app` | `https://nevermined.app` | `https://embed.nevermined.app` | `eip155:8453` (Base Mainnet) | `live:` |\n\nOnly `sandbox` and `live` are public. Use the exact base URL — never infer it.\n\n## What needs a human (once) vs. fully programmatic\n\n| Step | Human? |\n|---|---|\n| Get the first API key | **Yes, once** (browser sign-in) |\n| Enroll a card | **Yes, once** (browser; skip entirely for stablecoins) |\n| Check payment methods, create delegation, get token, settle, register, status, revenue | No — fully programmatic |\n\n---\n\n## 1. Get a Nevermined API key\n\nYou cannot mint the first key yourself.\n\n**Option A — embedded login (key returns automatically).** Host an HTTP server on `127.0.0.1:<port>` with a `/callback` route, then have your human open:\n\n```\nhttps://nevermined.app/auth/cli?callback_url=http://127.0.0.1:<port>/callback\n```\n\nAfter sign-in the browser hits `http://127.0.0.1:<port>/callback?nvm_api_key=<api-key>`. Read `nvm_api_key`, store it, reuse it.\n\n**Option B — manual paste.** Human signs in at [nevermined.app](https://nevermined.app) → Settings → Global NVM API Keys → **+ New API Key**, and pastes it back. Or opens `https://nevermined.app/auth/cli` (no `callback_url`) to read the key on screen.\n\nA `sandbox` key starts with `sandbox`; a `live` key with `live`.\n\n---\n\n## 2. Check your payment methods\n\n```bash\ncurl -s -H \"Authorization: Bearer $NVM_API_KEY\" \\\n  https://api.sandbox.nevermined.app/api/v1/payment-methods\n```\n\nResponse — array of payment methods:\n\n```json\n[\n  {\n    \"id\": \"pm_1Q...\",\n    \"type\": \"card\",\n    \"brand\": \"visa\",\n    \"last4\": \"4242\",\n    \"expMonth\": 12,\n    \"expYear\": 2030,\n    \"alias\": \"My Card\",\n    \"provider\": \"stripe\",\n    \"status\": \"Active\",\n    \"allowedApiKeyIds\": null\n  }\n]\n```\n\nA **stablecoin** method exists by default (fund it to pay immediately). A **card** method only appears after the"},{"path":"references/client-integration.md","content":"# Client-Side Integration (Subscriber Flow)\n\nHow to purchase plans, generate x402 tokens, and call payment-protected APIs as a subscriber.\n\n> ⚠️ **Run examples in `sandbox` first.** `orderPlan` charges money in `live`, and `delegationConfig` grants the platform pre-authorized spending up to `spendingLimitCents` for `durationSecs` seconds. Examples below use a small sandbox-friendly budget (`100¢` over `1h`); raise per use-case after explicit review.\n\n## Overview\n\nAs a subscriber (consumer of a paid API/agent), you:\n1. Order a payment plan\n2. Check your credit balance\n3. Generate an x402 access token\n4. Send requests with the `payment-signature` header\n5. Decode the settlement receipt from the `payment-response` header\n\n## Pure-REST purchase (no SDK)\n\nAn autonomous agent can complete the whole subscriber flow with plain HTTP — no SDK install. Send `Authorization: Bearer $NVM_API_KEY` on each call.\n\n```bash\n# 1. Get an x402 access token (create the delegation first via /delegation/create, then pass its delegationId)\ncurl -s -X POST -H \"Authorization: Bearer $NVM_API_KEY\" -H \"Content-Type: application/json\" \\\n  -d '{ \"accepted\": { \"scheme\": \"nvm:erc4337\", \"network\": \"eip155:84532\", \"planId\": \"<PLAN_ID>\" },\n        \"delegationConfig\": { \"delegationId\": \"<DELEGATION_ID>\" } }' \\\n  https://api.sandbox.nevermined.app/api/v1/x402/permissions\n# → { \"accessToken\": \"...\" }\n\n# 2. Settle (proof of purchase). For a plan top-up, resource.url is the plan URL.\ncurl -s -X POST -H \"Authorization: Bearer $NVM_API_KEY\" -H \"Content-Type: application/json\" \\\n  -d '{ \"paymentRequired\": { \"x402Version\": 2, \"resource\": { \"url\": \"<PLAN_OR_RESOURCE_URL>\" },\n          \"accepts\": [ { \"scheme\": \"nvm:erc4337\", \"network\": \"eip155:84532\", \"planId\": \"<PLAN_ID>\", \"extra\": {} } ],\n          \"extensions\": {} },\n        \"x402AccessToken\": \"<accessToken>\" }' \\\n  https://api.sandbox.nevermined.app/api/v1/x402/settle\n# → { \"success\": true, \"billingModel\": \"credits\", \"creditsRedeemed\": \"1\", \"remainingBalance\": \"999\", \"transaction\": \"0x...\" }\n```\n\n- **Card payment:** switch `scheme` to `nvm:card-delegation` and `network` to `stripe` (or `braintree`/`visa`) in both calls.\n- **Calling a protected agent directly:** skip building `paymentRequired` — send the access token as the `payment-signature` header; the agent settles for you and returns the receipt in the `payment-response` header.\n- **Proof of purchase — read `billingModel` first.** On a `credits` plan it is `success: true` and `creditsRedeemed > 0`. On a `pay-as-you-go` plan there is no credit balance, so `creditsRedeemed` and `remainingBalance` are always the string `\"0\"` even on a successful charge; the proof is `success: true` plus a non-empty `orderTx` (fiat) or `transaction` (crypto). Never gate on `creditsRedeemed` alone — on a card rail it reports a real charge as a decline and invites a retry. If `billingModel` is missing entirely the deployment predates it: apply the `credits` rule.\n\nFull runbook with API-key retrieval, card en"}],"languages":[],"docsSourceLabel":"CLAWHUB","editorialOverview":null,"editorialQuality":{"score":100,"threshold":65,"status":"thin","wordCount":1681,"uniquenessScore":43,"reasons":["uniqueness-below-45"]}},"media":{"evidence":{"source":"no-media","verified":false,"confidence":"low","updatedAt":"2026-10-10T16:20:03.897Z","emptyReason":"No screenshots, media assets, or demo links are available."},"primaryImageUrl":null,"mediaAssetCount":0,"assets":[],"demoUrl":null},"ownerResources":{"evidence":{"source":"unclaimed","verified":false,"confidence":"low","updatedAt":"2026-10-10T16:20:03.897Z","emptyReason":"This page has not been claimed by the agent owner."},"hasCustomPage":false,"customPageUpdatedAt":null,"customLinks":[],"structuredLinks":{"docsUrl":null,"demoUrl":null,"supportUrl":null,"pricingUrl":null,"statusUrl":null},"customPage":null},"relatedAgents":{"evidence":{"source":"protocol-neighbors","verified":false,"confidence":"medium","updatedAt":"2026-10-10T21:44:14.224Z","emptyReason":null},"items":[{"id":"8ebccd8e-3863-4187-8355-c3f14e1f9edf","entityType":"agent","canonicalPath":"/agent/iofficeai-aionui","slug":"iofficeai-aionui","name":"AionUi","description":"Free, local, open-source 24/7 Cowork app and OpenClaw for Gemini CLI, Claude Code, Codex, OpenCode, Qwen Code, Goose CLI, Auggie, and more | 🌟 Star if you like it!","url":"https://github.com/iOfficeAI/AionUi","homepage":"https://www.aionui.com","source":"GITHUB_REPOS","protocols":["MCP","OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-10-09T19:11:12.944Z","createdAt":"2026-02-25T03:38:16.584Z","downloads":null},{"id":"b917f68a-ebff-438e-84f8-3f4b2494c0bc","entityType":"agent","canonicalPath":"/agent/activepieces-activepieces","slug":"activepieces-activepieces","name":"activepieces","description":"AI Agents & MCPs & AI Workflow Automation • (~400 MCP servers for AI agents) • AI Automation / AI Agent with MCPs • AI Workflows & AI Agents • MCPs for AI Agents","url":"https://github.com/activepieces/activepieces","homepage":"https://www.activepieces.com","source":"GITHUB_REPOS","protocols":["OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-04-15T02:22:12.426Z","createdAt":"2026-02-25T03:38:12.412Z","downloads":null},{"id":"5cb26759-3a39-483f-94cf-276a98c13bb8","entityType":"agent","canonicalPath":"/agent/cherryhq-cherry-studio","slug":"cherryhq-cherry-studio","name":"cherry-studio","description":"AI productivity studio with smart chat, autonomous agents, and 300+ assistants. Unified access to frontier LLMs","url":"https://github.com/CherryHQ/cherry-studio","homepage":"https://cherry-ai.com","source":"GITHUB_REPOS","protocols":["MCP","OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-04-11T14:38:40.986Z","createdAt":"2026-02-25T03:38:19.379Z","downloads":null},{"id":"6f6582d0-5d76-4f0f-b81d-86520247950b","entityType":"agent","canonicalPath":"/agent/copilotkit-copilotkit","slug":"copilotkit-copilotkit","name":"CopilotKit","description":"The Frontend for Agents & Generative UI. React + Angular","url":"https://github.com/CopilotKit/CopilotKit","homepage":"https://docs.copilotkit.ai","source":"GITHUB_REPOS","protocols":["OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-03-25T09:50:57.846Z","createdAt":"2026-02-25T03:39:14.617Z","downloads":null}],"links":{"hub":"/agent","source":"/agent/source/clawhub","protocols":[{"label":"OpenClaw","href":"/agent/protocol/openclew"}]}}}