> ## Documentation Index
> Fetch the complete documentation index at: https://docs.nevermined.app/llms.txt
> Use this file to discover all available pages before exploring further.

# X402 Protocol

> Understand the X402 payment protocol for HTTP-based AI agent authentication and authorization

# X402 Protocol

The X402 protocol is a payment-aware HTTP extension that enables AI agents to require and verify payments for API access. This guide provides a complete overview of X402 implementation in the Nevermined Payments Library.

> 🔐 **Bearer-token hygiene.** The `payment-signature` header is a bearer credential — anyone holding it can spend the associated plan's credits until it expires. Send it only over HTTPS, never log the full value, and configure your log/trace exporters (pino, winston, OpenTelemetry) to redact `payment-signature`, `authorization`, and `cookie` headers by default.

## Overview of X402

X402 is an HTTP-based protocol for payment-protected resources:

* **402 Payment Required**: HTTP status code for payment requests
* **payment-signature**: Header containing payment credentials (X402 v2)
* **PAYMENT-REQUIRED**: Header with payment requirements in 402 responses
* **PAYMENT-RESPONSE**: Header with payment settlement details in success responses
* **Cryptographic Signatures**: ERC-4337 account abstraction for secure payments

## Supported Schemes

Nevermined supports two x402 payment schemes:

| Scheme                | Network                           | Use Case         | Settlement                      |
| --------------------- | --------------------------------- | ---------------- | ------------------------------- |
| `nvm:erc4337`         | `eip155:84532`                    | Crypto payments  | ERC-4337 UserOps + session keys |
| `nvm:card-delegation` | `stripe` \| `braintree` \| `visa` | Fiat/credit card | Provider charge + credit burn   |

The scheme is determined by the plan's pricing configuration. Plans with `isCrypto: false` use `nvm:card-delegation`; all others use `nvm:erc4337`. The SDK auto-detects the scheme via `resolveScheme()`. The `network` value within `nvm:card-delegation` is determined by which provider issued the delegation being consumed (`stripe`, `braintree`, or `visa`).

### Visa support

Visa delegations use the same `nvm:card-delegation` scheme and SDK surface as Stripe and Braintree, but two steps must happen in a **browser** before the SDK can consume them:

1. **Card enrolment** — the cardholder enrols a Visa card through VGS Collect (PCI-compliant iframe) in the Nevermined webapp. The card is bound to a Visa Agentic Token via the VGS Credential Management Platform.
2. **Delegation creation** — the cardholder approves a delegation via a WebAuthn/passkey (FIDO) device-binding ceremony embedded by Visa VTS. This produces a single-use `assuranceData` blob bound to the spending limit + duration + merchant context.

Both steps require a real DOM and a user gesture, so the SDK cannot perform them programmatically. Once a Visa delegation exists, the SDK consumes it identically to Stripe/Braintree — see [Reusing Existing Delegations](#reusing-existing-delegations).

## X402 Version 2 Specification

The Nevermined Payments Library implements X402 v2, which uses:

* `payment-signature` header for access tokens (replaces Authorization)
* `PAYMENT-REQUIRED` header for payment requirements (replaces custom formats)
* `PAYMENT-RESPONSE` header for settlement receipts
* Structured payment credentials with cryptographic signatures

## Generate X402 Access Tokens

The supported flow is **create-first**: create a delegation once with
`payments.delegation.createDelegation(...)`, then request access tokens by
passing only its `delegationId`. **Both schemes (`nvm:erc4337` and
`nvm:card-delegation`) require a `delegationConfig`** — the older
"just pass planId + agentId" shape no longer mints a token and surfaces
`BCK.X402.0030` ("Required token-generation input is missing or incomplete";
the `details` field names the missing input) at the backend.

```typescript theme={null}
import { Payments, EnvironmentName, X402TokenOptions } from '@nevermined-io/payments'

const subscriberPayments = Payments.getInstance({
  nvmApiKey: process.env.SUBSCRIBER_API_KEY!,
  environment: 'sandbox' as EnvironmentName,
})

// 1. Create a delegation once. `currency` is required: 'usdc' for the
//    crypto (erc4337) scheme, 'usd'/'eur'/… for card providers.
const { delegationId } = await subscriberPayments.delegation.createDelegation({
  provider: 'erc4337',
  spendingLimitCents: 1000, // $10 cap
  durationSecs: 86_400, // 1 day
  currency: 'usdc',
})

// 2. Request a token by delegationId. Reuse this delegation for every
//    subsequent token request until it expires or is exhausted.
const tokenOptions: X402TokenOptions = {
  scheme: 'nvm:erc4337',
  delegationConfig: { delegationId },
}

const { accessToken } = await subscriberPayments.x402.getX402AccessToken(
  planId, // Required: Plan ID
  agentId, // Optional: Agent ID (restricts token to specific agent)
  tokenOptions, // Required: scheme + delegationConfig
)

console.log('X402 access token generated')
```

> ⚠️ **Inline create-on-the-fly is deprecated.** Passing creation fields
> (`spendingLimitCents`, `durationSecs`, `providerPaymentMethodId`, `cardId`,
> `currency`, `merchantAccountId`, `maxTransactions`) directly in
> `delegationConfig` instead of a `delegationId` still works, but
> `getX402AccessToken` now emits a runtime deprecation warning. Create the
> delegation first (above) and pass only `{ delegationId }`.

### Generate Tokens via Nevermined App

Users can also generate X402 access tokens through the Nevermined App:

1. Visit [nevermined.app/permissions/agent-permissions](https://nevermined.app/permissions/agent-permissions)
2. Select the plan you've purchased
3. Configure token parameters (agent, expiration, limits)
4. Generate and copy the X402 access token
5. Use the token in API requests

This provides a user-friendly interface for non-technical users to generate tokens without code.

### Generate Card-Delegation Tokens

For fiat plans using `nvm:card-delegation`, create the delegation first with
`createDelegation` (passing the card's `providerPaymentMethodId`), then request
tokens by its `delegationId`. `currency` is required on creation:

```typescript theme={null}
import { X402TokenOptions } from '@nevermined-io/payments'

// 1. Create a USD card delegation once.
const { delegationId: usdDelegationId } =
  await subscriberPayments.delegation.createDelegation({
    provider: 'stripe',
    providerPaymentMethodId: 'pm_1AbCdEfGhIjKlM',
    spendingLimitCents: 10000, // $100.00
    durationSecs: 2592000, // 30 days
    currency: 'usd',
    maxTransactions: 100,
  })

// 2. Request a token by delegationId (reuse for every subsequent request).
const tokenOptions: X402TokenOptions = {
  scheme: 'nvm:card-delegation',
  delegationConfig: { delegationId: usdDelegationId },
}

const { accessToken } = await subscriberPayments.x402.getX402AccessToken(
  planId,
  agentId,
  tokenOptions,
)
```

A EUR delegation is the same call with `currency: 'eur'`. The delegation's
currency is fixed at creation, so you create one delegation per currency and
reuse each by its `delegationId`.

### Reusing Existing Delegations

Passing `delegationConfig: { delegationId }` is the supported pattern for every
provider, and the **only** supported pattern for Visa delegations (which cannot
be created from the SDK). Reuse one delegation across multiple agents that share
a single spending budget:

```typescript theme={null}
const tokenOptions: X402TokenOptions = {
  scheme: 'nvm:card-delegation',
  delegationConfig: {
    delegationId: 'a1b2c3d4-e5f6-7890-abcd-ef1234567890',
  }
}

const { accessToken } = await subscriberPayments.x402.getX402AccessToken(
  planId,
  agentId,
  tokenOptions,
)
```

When `delegationId` is provided, the backend verifies that the delegation is active and that the requesting API key has access, then returns its existing token without creating a new delegation. The provider (`stripe`, `braintree`, or `visa`) is inferred from the delegation record on the server.

To scope a token request to a specific NVM API key, add `apiKeyId` alongside
`delegationId` — both fields stay active (non-deprecated):

```typescript theme={null}
delegationConfig: { delegationId: '…', apiKeyId: 'key-uuid' }
```

### Deprecated: inline create-on-the-fly

> ⚠️ **Deprecated.** Supplying creation fields directly in `delegationConfig`
> instead of a `delegationId` (e.g. `providerPaymentMethodId` +
> `spendingLimitCents`, a bare `cardId`, or an identifier-less "auto-select"
> shape) still creates a delegation on the fly, but `getX402AccessToken` now
> emits a runtime deprecation warning. Use the create-first pattern above
> (`createDelegation` → `{ delegationId }`); inline creation will be removed in
> a future major release.

### CardDelegationConfig Reference

| Field                     | Type     | Status     | Description                                               |
| ------------------------- | -------- | ---------- | --------------------------------------------------------- |
| `delegationId`            | `string` | Active     | Existing delegation UUID to reuse — the supported path    |
| `apiKeyId`                | `string` | Active     | NVM API Key ID to scope the token request to              |
| `cardId`                  | `string` | Deprecated | Payment method UUID to target (inline create)             |
| `providerPaymentMethodId` | `string` | Deprecated | Stripe payment method ID (e.g., `pm_...`) (inline create) |
| `spendingLimitCents`      | `number` | Deprecated | Max spending in cents (inline create)                     |
| `durationSecs`            | `number` | Deprecated | Duration in seconds (inline create)                       |
| `currency`                | `string` | Deprecated | Currency code (inline create)                             |
| `planId`                  | `string` | Deprecated | Plan ID to scope a new delegation to (inline create)      |
| `merchantAccountId`       | `string` | Deprecated | Stripe Connect account ID (inline create)                 |
| `maxTransactions`         | `number` | Deprecated | Max transactions allowed (inline create)                  |

The deprecated fields apply only to inline create-on-the-fly. Create the
delegation with [`createDelegation`](#createdelegation) and pass only
`delegationId` (optionally `apiKeyId`) here.

### Auto Scheme Resolution

Use `resolveScheme()` to auto-detect the correct scheme from plan metadata:

```typescript theme={null}
import { resolveScheme } from '@nevermined-io/payments'

// Auto-detect scheme from plan metadata (cached for 5 minutes)
const scheme = await resolveScheme(payments, planId)
// Returns "nvm:erc4337" for crypto plans, "nvm:card-delegation" for fiat plans

// Explicit override
const scheme = await resolveScheme(payments, planId, 'nvm:card-delegation')
```

### DelegationAPI

Manage payment methods and delegations for card delegation:

```typescript theme={null}
import { DelegationAPI, PaymentMethodSummary } from '@nevermined-io/payments'

const delegationApi = DelegationAPI.getInstance(payments.options)

// List enrolled payment methods (every provider)
const methods: PaymentMethodSummary[] = await delegationApi.listPaymentMethods()

// Restrict the result to a single provider with the optional `provider` filter
const stripeMethods: PaymentMethodSummary[] = await delegationApi.listPaymentMethods({
  provider: 'stripe',
})

for (const method of methods) {
  console.log(`${method.brand} ****${method.last4} (expires ${method.expMonth}/${method.expYear})`)
  if (method.allowedApiKeyIds) {
    console.log(`  Restricted to API keys: ${method.allowedApiKeyIds.join(', ')}`)
  }
}
```

`listPaymentMethods` accepts an optional `ListOptions`:

| Option       | Type                                                                    | Description                                                                                                                                           |
| ------------ | ----------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- |
| `provider`   | `DelegationProvider` (`'stripe' \| 'braintree' \| 'visa' \| 'erc4337'`) | Server-side filter that restricts the result to payment methods backed by this provider. Omit it (the default) to return methods from every provider. |
| `accessible` | `boolean`                                                               | When `true`, return only methods accessible to the requesting API key.                                                                                |

#### Update Payment Method

Restrict a card to specific NVM API Keys so only designated agents can use it:

```typescript theme={null}
await delegationApi.updatePaymentMethod('pm-uuid-here', {
  alias: 'Production Card',
  allowedApiKeyIds: ['sk-agent-1', 'sk-agent-2'],  // Only these API keys can use this card
})

// Remove restrictions (any API key can use the card)
await delegationApi.updatePaymentMethod('pm-uuid-here', {
  allowedApiKeyIds: null,
})
```

#### List Delegations

Retrieve all delegations for the authenticated user:

```typescript theme={null}
const { delegations, totalResults } = await delegationApi.listDelegations()

console.log(`Total delegations: ${totalResults}`)
for (const d of delegations) {
  console.log(`${d.delegationId} - ${d.status} (${d.remainingBudgetCents} cents remaining)`)
  if (d.apiKeyId) {
    console.log(`  Restricted to API key: ${d.apiKeyId}`)
  }
}
```

#### createDelegation

Create a delegation once, then reuse it across token requests by its
`delegationId` (the create-first pattern). This is the supported way to
provision spending authority for `nvm:erc4337` and `nvm:card-delegation` —
prefer it over inline create-on-the-fly in `getX402AccessToken`.

```typescript theme={null}
// Crypto (erc4337): currency must be 'usdc'.
const { delegationId } = await delegationApi.createDelegation({
  provider: 'erc4337',
  spendingLimitCents: 100000, // $1000 cap
  durationSecs: 604800, // 1 week
  currency: 'usdc',
})

// Card (stripe / braintree): pass the enrolled card's providerPaymentMethodId.
const { delegationId: cardDelegationId } = await delegationApi.createDelegation({
  provider: 'stripe',
  providerPaymentMethodId: 'pm_1AbCdEfGhIjKlM',
  spendingLimitCents: 10000,
  durationSecs: 2592000,
  currency: 'usd',
})
```

`CreateDelegationPayload` fields:

| Field                     | Type                                                        | Required  | Description                                                                                                                                                                |
| ------------------------- | ----------------------------------------------------------- | --------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `provider`                | `'stripe' \| 'braintree' \| 'visa' \| 'erc4337'`            | Yes       | Delegation provider                                                                                                                                                        |
| `spendingLimitCents`      | `number`                                                    | Yes       | Maximum spending limit in cents                                                                                                                                            |
| `durationSecs`            | `number`                                                    | Yes       | Delegation lifetime in seconds                                                                                                                                             |
| `currency`                | `DelegationCurrency` (`'usd' \| 'eur' \| 'usdc' \| 'eurc'`) | Yes       | Currency code — `'usdc'`/`'eurc'` for erc4337, `'usd'`/`'eur'` for card providers. No silent default; the backend requires it.                                             |
| `providerPaymentMethodId` | `string`                                                    | Card only | Payment method ID (Stripe `pm_...`, Braintree vault token, Visa Agentic token id)                                                                                          |
| `planId`                  | `string`                                                    | No        | Optional and additive — delegations are plan-agnostic by default; supply `planId` to bind the delegation to a single plan. (Visa is always plan-specific and requires it.) |
| `merchantAccountId`       | `string`                                                    | No        | Stripe Connect account ID or Braintree merchantId                                                                                                                          |
| `maxTransactions`         | `number`                                                    | No        | Maximum number of transactions allowed                                                                                                                                     |
| `apiKeyId`                | `string`                                                    | No        | NVM API Key ID to scope the delegation to                                                                                                                                  |

> Visa delegations require a browser-side device-binding ceremony and cannot be
> created from the SDK — see [Visa support](#visa-support). Create them in the
> Nevermined webapp, then consume them here by `delegationId`.

#### DelegationListResponse Fields

`listDelegations()` resolves to a `DelegationListResponse` object:

| Field          | Type                  | Description                     |
| -------------- | --------------------- | ------------------------------- |
| `delegations`  | `DelegationSummary[]` | Array of delegation records     |
| `totalResults` | `number`              | Total number of delegations     |
| `page`         | `number`              | Current page number             |
| `offset`       | `number`              | Offset into the full result set |

#### DelegationSummary Fields

Each item in the `delegations` array is a `DelegationSummary`:

| Field                     | Type             | Description                                                         |
| ------------------------- | ---------------- | ------------------------------------------------------------------- |
| `delegationId`            | `string`         | Unique delegation identifier                                        |
| `provider`                | `string`         | Payment provider (`stripe`, `braintree`, or `visa`)                 |
| `providerPaymentMethodId` | `string`         | Provider-side payment method ID                                     |
| `status`                  | `string`         | Delegation status (`Active`, `Revoked`, etc.)                       |
| `spendingLimitCents`      | `string`         | Maximum spendable amount in cents                                   |
| `amountSpentCents`        | `string`         | Amount already spent in cents                                       |
| `remainingBudgetCents`    | `string`         | Remaining budget in cents                                           |
| `currency`                | `string`         | Currency code (e.g., `usd`)                                         |
| `transactionCount`        | `number`         | Number of transactions made                                         |
| `expiresAt`               | `string`         | Expiry timestamp (ISO 8601)                                         |
| `createdAt`               | `string`         | Creation timestamp (ISO 8601)                                       |
| `apiKeyId`                | `string \| null` | API key this delegation is restricted to, or `null` if unrestricted |

#### PaymentMethodSummary Fields

| Field              | Type               | Description                                               |
| ------------------ | ------------------ | --------------------------------------------------------- |
| `id`               | `string`           | Payment method ID (e.g., `pm_...`)                        |
| `brand`            | `string`           | Card brand (e.g., `visa`, `mastercard`)                   |
| `last4`            | `string`           | Last 4 digits of the card number                          |
| `expMonth`         | `number`           | Card expiration month                                     |
| `expYear`          | `number`           | Card expiration year                                      |
| `allowedApiKeyIds` | `string[] \| null` | API keys allowed to use this card (`null` = unrestricted) |

## X402 Access Token Structure

The access token is a JWT containing an X402 v2 payment credential:

```json theme={null}
{
  "x402Version": 2,
  "accepted": {
    "scheme": "nvm:erc4337",           // Payment scheme
    "network": "eip155:84532",         // Blockchain network (Base Sepolia)
    "planId": "plan-123",              // Payment plan ID
    "extra": {
      "version": "1",                  // Extra version info
      "agentId": "did:nv:agent-456"    // Optional agent restriction
    }
  },
  "payload": {
    "signature": "0x...",              // Cryptographic signature
    "authorization": {
      "from": "0xSubscriberAddress",   // Subscriber's wallet address
      "sessionKeysProvider": "zerodev", // Session key provider
      "sessionKeys": []                // Session keys for gasless transactions
    }
  },
  "extensions": {}                     // Optional extensions
}
```

### Card-Delegation Token Structure

For fiat plans using `nvm:card-delegation`, the token contains a JWT-based delegation authorization:

```json theme={null}
{
  "x402Version": 2,
  "accepted": {
    "scheme": "nvm:card-delegation",
    "network": "stripe",
    "planId": "plan-123",
    "extra": {
      "version": "1",
      "agentId": "did:nv:agent-456"
    }
  },
  "payload": {
    "token": "eyJhbGciOiJSUzI1NiIs...",
    "authorization": {
      "from": "0xSubscriberAddress",
      "sessionKeys": [{ "id": "redeem", "data": "0xabc123..." }]
    }
  },
  "extensions": {}
}
```

### Token Components

* **x402Version**: Protocol version (2 for current spec)
* **accepted**: Payment method specification
  * **scheme**: `nvm:erc4337` for crypto or `nvm:card-delegation` for fiat
  * **network**: `eip155:84532` (Base Sepolia) for crypto, one of `stripe`, `braintree`, or `visa` for fiat
  * **planId**: The payment plan being used
  * **extra**: Additional metadata (version, agentId, etc.)
* **payload**: Payment authorization
  * **signature** (erc4337): Cryptographic proof of payment authorization
  * **token** (card-delegation): Signed JWT encoding the delegation claims
  * **authorization**: Subscriber identity and session keys
* **extensions**: Optional protocol extensions

## Verify X402 Permissions

Agents verify tokens before executing requests:

```typescript theme={null}
import { Payments, EnvironmentName } from '@nevermined-io/payments'
import { buildPaymentRequired } from '@nevermined-io/payments'

const agentPayments = Payments.getInstance({
  nvmApiKey: process.env.NVM_API_KEY!,  // Builder/agent API key
  environment: 'sandbox' as EnvironmentName,
})

// Build payment required specification
const paymentRequired = buildPaymentRequired(planId, {
  endpoint: '/api/v1/tasks',
  agentId: agentId,
  httpVerb: 'POST',
  network: 'eip155:84532',
  description: 'Task execution API',
})

// Verify subscriber permissions
const verification = await agentPayments.facilitator.verifyPermissions({
  paymentRequired,
  x402AccessToken: accessToken,
  maxAmount: 2n,  // Max credits to verify
})

if (verification.isValid) {
  console.log('✓ Permissions verified')
  console.log(`Payer: ${verification.payer}`)
} else {
  console.log(`✗ Verification failed: ${verification.invalidReason}`)
}
```

### Verification Response

```typescript theme={null}
interface VerifyPermissionsResult {
  isValid: boolean           // True if token is valid
  invalidReason?: string     // Reason for invalidity (if isValid is false)
  payer?: string             // Address of the payer's wallet
  agentRequestId?: string    // Agent request ID for observability tracking (Nevermined extension)
  urlMatching?: string       // URL pattern that matched the endpoint (Nevermined extension)
  agentRequest?: StartAgentRequest  // Agent request context for observability (Nevermined extension)
}

interface StartAgentRequest {
  agentRequestId: string     // Unique request identifier
  agentName: string          // Name of the agent
  agentId: string            // Agent identifier
  balance: PlanBalance       // Current plan balance (planId, balance, pricePerCredit, etc.)
  urlMatching: string        // URL pattern that was matched
  verbMatching: string       // HTTP verb that was matched
  batch: boolean             // Whether this is a batch request
}
```

## Settle X402 Permissions

After successful execution, burn credits:

```typescript theme={null}
// Settle permissions (burn credits)
const settlement = await agentPayments.facilitator.settlePermissions({
  paymentRequired,
  x402AccessToken: accessToken,
  maxAmount: 2n,  // Credits to burn
  batch: false,   // Batch settlement (optional)
  marginPercent: 5,  // Add 5% margin (optional)
  agentRequestId: verification.agentRequest?.agentRequestId,  // From verification
})

console.log(`✓ Settlement successful`)
console.log(`Transaction: ${settlement.transaction}`)
console.log(`Credits burned: ${settlement.creditsRedeemed}`)
console.log(`Remaining balance: ${settlement.remainingBalance}`)
```

### Settlement Response

```typescript theme={null}
interface SettlePermissionsResult {
  success: boolean          // True if settlement succeeded
  transaction: string       // Blockchain transaction hash
  creditsRedeemed: string   // Credits burned
  remainingBalance: string  // Subscriber's remaining credits
  network: string          // Blockchain network
}
```

## HTTP Headers (X402 v2)

### payment-signature Header

Subscribers include this header in requests:

```http theme={null}
POST /api/v1/tasks HTTP/1.1
Host: agent.example.com
Content-Type: application/json
payment-signature: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...

{"prompt": "Hello"}
```

### PAYMENT-REQUIRED Header (402 Response)

Agents return this header when payment is required:

```http theme={null}
HTTP/1.1 402 Payment Required
Content-Type: application/json
PAYMENT-REQUIRED: eyJ4NDAyVmVyc2lvbiI6MiwicmVzb3VyY2UiOnsidXJsIjoiL2FwaS92MS90YXNrcyJ9...

{"error": "Payment required"}
```

The header contains base64-encoded payment requirement JSON. The `scheme` and `network` vary by plan type:

**Crypto plan:**

```json theme={null}
{
  "x402Version": 2,
  "resource": {
    "url": "/api/v1/tasks",
    "description": "Task execution API",
    "mimeType": "application/json"
  },
  "accepts": [
    {
      "scheme": "nvm:erc4337",
      "network": "eip155:84532",
      "planId": "plan-123",
      "extra": {
        "version": "1",
        "agentId": "did:nv:agent-456"
      }
    }
  ],
  "extensions": {}
}
```

**Fiat plan:**

```json theme={null}
{
  "x402Version": 2,
  "resource": {
    "url": "/api/v1/tasks",
    "description": "Task execution API",
    "mimeType": "application/json"
  },
  "accepts": [
    {
      "scheme": "nvm:card-delegation",
      "network": "stripe",
      "planId": "plan-123",
      "extra": {
        "version": "1",
        "agentId": "did:nv:agent-456"
      }
    }
  ],
  "extensions": {}
}
```

### PAYMENT-RESPONSE Header (Success)

Agents include this header in successful responses:

```http theme={null}
HTTP/1.1 200 OK
Content-Type: application/json
PAYMENT-RESPONSE: eyJzdWNjZXNzIjp0cnVlLCJ0cmFuc2FjdGlvbiI6IjB4Li4uIn0=

{"result": "Task completed"}
```

The header contains base64-encoded settlement details:

```json theme={null}
{
  "success": true,
  "network": "eip155:84532",
  "transaction": "0x...",
  "creditsRedeemed": "2",
  "remainingBalance": "98"
}
```

## Complete X402 Flow

### Subscriber Side

```typescript theme={null}
import { Payments, EnvironmentName } from '@nevermined-io/payments'

const subscriberPayments = Payments.getInstance({
  nvmApiKey: process.env.SUBSCRIBER_API_KEY!,
  environment: 'sandbox' as EnvironmentName,
})

// 1. Create a delegation once (currency required; 'usdc' for erc4337),
//    then generate an access token by its delegationId.
const { delegationId } = await subscriberPayments.delegation.createDelegation({
  provider: 'erc4337',
  spendingLimitCents: 1000,
  durationSecs: 86_400,
  currency: 'usdc',
})
const { accessToken } = await subscriberPayments.x402.getX402AccessToken(planId, agentId, {
  scheme: 'nvm:erc4337',
  delegationConfig: { delegationId },
})

// 2. Make request with payment-signature header
const response = await fetch('https://agent.example.com/api/v1/tasks', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'payment-signature': accessToken,
  },
  body: JSON.stringify({ prompt: 'Hello, agent!' }),
})

// 3. Handle response
if (response.status === 402) {
  // Payment required - need to purchase plan or top up
  const paymentRequired = response.headers.get('PAYMENT-REQUIRED')
  console.error('Payment required:', paymentRequired)
} else {
  const result = await response.json()
  const paymentResponse = response.headers.get('PAYMENT-RESPONSE')
  console.log('Success:', result)
  console.log('Payment:', paymentResponse)
}
```

### Agent Side

```typescript theme={null}
import express from 'express'
import { Payments, EnvironmentName } from '@nevermined-io/payments'
import { buildPaymentRequired } from '@nevermined-io/payments'

const app = express()
app.use(express.json())

const agentPayments = Payments.getInstance({
  nvmApiKey: process.env.NVM_API_KEY!,
  environment: 'sandbox' as EnvironmentName,
})

app.post('/api/v1/tasks', async (req, res) => {
  // 1. Extract token
  const accessToken = req.headers['payment-signature'] as string

  if (!accessToken) {
    const paymentRequired = buildPaymentRequired(planId, {
      endpoint: req.url,
      agentId: agentId,
      httpVerb: req.method,
    })

    return res
      .status(402)
      .set('PAYMENT-REQUIRED', Buffer.from(JSON.stringify(paymentRequired)).toString('base64'))
      .json({ error: 'Payment required' })
  }

  // 2. Build payment required
  const paymentRequired = buildPaymentRequired(planId, {
    endpoint: req.url,
    agentId: agentId,
    httpVerb: req.method,
  })

  try {
    // 3. Verify permissions
    const verification = await agentPayments.facilitator.verifyPermissions({
      paymentRequired,
      x402AccessToken: accessToken,
      maxAmount: 2n,
    })

    if (!verification.isValid) {
      return res
        .status(402)
        .set('PAYMENT-REQUIRED', Buffer.from(JSON.stringify(paymentRequired)).toString('base64'))
        .json({ error: 'Insufficient credits' })
    }

    // 4. Execute task
    const result = await processTask(req.body)

    // 5. Settle permissions
    const settlement = await agentPayments.facilitator.settlePermissions({
      paymentRequired,
      x402AccessToken: accessToken,
      maxAmount: 2n,
    })

    // 6. Return response with PAYMENT-RESPONSE header
    const paymentResponse = {
      success: settlement.success,
      network: settlement.network,
      transaction: settlement.transaction,
      creditsRedeemed: settlement.creditsRedeemed,
    }

    return res
      .status(200)
      .set('PAYMENT-RESPONSE', Buffer.from(JSON.stringify(paymentResponse)).toString('base64'))
      .json({ result })

  } catch (error) {
    res.status(500).json({ error: error.message })
  }
})

app.listen(3000)
```

## buildPaymentRequired Helper

Simplifies creating X402PaymentRequired objects:

```typescript theme={null}
import { buildPaymentRequired } from '@nevermined-io/payments'

// Scheme auto-detected from plan metadata when omitted
const paymentRequired = buildPaymentRequired(
  planId,
  {
    endpoint: '/api/v1/tasks',      // Resource URL
    agentId: 'did:nv:agent-456',    // Agent ID
    httpVerb: 'POST',               // HTTP method
    network: 'eip155:84532',        // Blockchain (default for nvm:erc4337)
    description: 'Task execution',  // Description
    scheme: 'nvm:erc4337'           // Optional: omit to auto-detect from plan metadata
  }
)
```

When `scheme` is set to `'nvm:card-delegation'`, the `network` is automatically set to `'stripe'`.

## Best Practices

1. **Always Verify Before Execute**: Never skip token verification
2. **Settle After Success**: Only burn credits after successful execution
3. **Use X402 v2 Headers**: Prefer `payment-signature` over Authorization
4. **Return 402 Properly**: Include `PAYMENT-REQUIRED` header with details
5. **Log Transactions**: Record settlement transaction hashes
6. **Handle Errors**: Provide clear error messages in 402 responses
7. **Token Reuse**: Subscribers can reuse tokens for multiple requests
8. **Restrict Cards to API Keys**: When running multiple agents, restrict each card to specific NVM API Keys using `allowedApiKeyIds` to prevent unauthorized spending
9. **Reuse Delegations**: Pass `delegationId` to reuse existing delegations instead of creating new ones on each request — this avoids delegation sprawl and keeps spending consolidated

## Related Documentation

* [Querying an Agent](./querying-an-agent) - How subscribers use X402 tokens
* [Validation of Requests](./validation-of-requests) - How agents verify and settle
* [MCP Integration](./mcp-integration) - Automatic X402 handling in MCP
* [A2A Integration](./a2a-integration) - Automatic X402 handling in A2A

***

**Source References**:

* `src/x402/token.ts` (getX402AccessToken)
* `src/x402/delegation-api.ts` (DelegationAPI: listPaymentMethods, listDelegations, updatePaymentMethod)
* `src/x402/facilitator-api.ts` (verifyPermissions, settlePermissions, buildPaymentRequired)
* `tests/e2e/test_x402_e2e.test.ts` (complete X402 flow)
