> ## Documentation Index
> Fetch the complete documentation index at: https://neverminedag-sync-api-changelog-995eeb3-27540816297.mintlify.site/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

Subscribers generate access tokens to query agents. **Both schemes
(`nvm:erc4337` and `nvm:card-delegation`) require a `delegationConfig`** —
the older "just pass planId + agentId" shape no longer mints a token and
will surface `BCK.X402.0030` ("Required token-generation input is missing
or incomplete"; the `details` field names the missing input, e.g.
"delegationConfig is required …") 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,
})

// Crypto (nvm:erc4337) example — auto-creates a delegation on first call
const tokenOptions: X402TokenOptions = {
  scheme: 'nvm:erc4337',
  delegationConfig: {
    spendingLimitCents: 1000, // $10 cap
    durationSecs: 86_400, // 1 day
  },
}

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')
```

To reuse a previously-minted delegation rather than auto-creating one,
pass `delegationConfig: { delegationId: '<uuid>' }` — the backend
verifies the delegation is still active and returns its bound token.

### 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`, pass `X402TokenOptions` with a `CardDelegationConfig`:

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

// USD card delegation
const tokenOptions: X402TokenOptions = {
  scheme: 'nvm:card-delegation',
  delegationConfig: {
    providerPaymentMethodId: 'pm_1AbCdEfGhIjKlM',
    spendingLimitCents: 10000,  // $100.00
    durationSecs: 2592000,       // 30 days
    currency: 'usd',
    maxTransactions: 100
  }
}

// EUR card delegation
const eurTokenOptions: X402TokenOptions = {
  scheme: 'nvm:card-delegation',
  delegationConfig: {
    providerPaymentMethodId: 'pm_1AbCdEfGhIjKlM',
    spendingLimitCents: 10000,  // €100.00 (in euro cents)
    durationSecs: 2592000,       // 30 days
    currency: 'eur',
    maxTransactions: 100
  }
}

// USD card delegation token
const { accessToken } = await subscriberPayments.x402.getX402AccessToken(
  planId,
  agentId,
  tokenOptions,
)

// EUR card delegation token
const { accessToken: eurAccessToken } = await subscriberPayments.x402.getX402AccessToken(
  planId,
  agentId,
  eurTokenOptions,
)
```

### Reusing Existing Delegations

Instead of creating a new delegation on every token request, you can reuse an existing delegation by passing its `delegationId`. This is useful when running multiple agents that should share a single spending budget, and is the **only** supported pattern for Visa delegations (which cannot be created from the SDK):

```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.

### Specifying a Card

You can target a specific enrolled card using `cardId`. The backend will look for an active delegation on that card or create a new one:

```typescript theme={null}
const tokenOptions: X402TokenOptions = {
  scheme: 'nvm:card-delegation',
  delegationConfig: {
    cardId: 'a1b2c3d4-e5f6-7890-abcd-ef1234567890',
    spendingLimitCents: 5000,  // Only used if a new delegation is created
    durationSecs: 604800,
  }
}
```

### Auto-Selection

When neither `cardId` nor `delegationId` is specified (and `providerPaymentMethodId` is omitted), the backend automatically selects the best card and delegation for the requesting API key. It finds cards accessible to the API key, looks for active delegations with remaining budget, and reuses one if available — otherwise creates a new delegation:

```typescript theme={null}
const tokenOptions: X402TokenOptions = {
  scheme: 'nvm:card-delegation',
  delegationConfig: {
    spendingLimitCents: 10000,
    durationSecs: 2592000,
  }
}
```

### CardDelegationConfig Reference

| Field                     | Type     | Required | Description                                 |
| ------------------------- | -------- | -------- | ------------------------------------------- |
| `delegationId`            | `string` | No       | Existing delegation UUID to reuse           |
| `cardId`                  | `string` | No       | Payment method UUID to target               |
| `providerPaymentMethodId` | `string` | No       | Stripe payment method ID (e.g., `pm_...`)   |
| `spendingLimitCents`      | `number` | No\*     | Max spending in cents (for new delegations) |
| `durationSecs`            | `number` | No\*     | Duration in seconds (for new delegations)   |
| `currency`                | `string` | No       | Currency code, defaults to `usd`            |
| `merchantAccountId`       | `string` | No       | Stripe Connect account ID                   |
| `maxTransactions`         | `number` | No       | Max transactions allowed                    |

\* Required when creating a new delegation. Ignored when reusing an existing one via `delegationId`.

### 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}`)
  }
}
```

#### 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. Generate access token (delegationConfig is required for both schemes)
const { accessToken } = await subscriberPayments.x402.getX402AccessToken(planId, agentId, {
  scheme: 'nvm:erc4337',
  delegationConfig: { spendingLimitCents: 1000, durationSecs: 86_400 },
})

// 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)
