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

# Querying Agents

> Generate X402 access tokens and make authenticated requests to AI agents

# Querying an Agent

After purchasing a payment plan, subscribers can generate X402 access tokens and use them to query AI agents. This guide explains how to get tokens and make authenticated requests.

> 🔐 **Treat access tokens like API keys.** The `accessToken` returned by `getX402AccessToken()` is a bearer credential that authorises spending against your plan. Send it only over HTTPS, never log its full value, and scrub the `payment-signature` header from any pino/winston/OpenTelemetry exporter. Use a redaction helper such as ``redactToken(t) => `${t.slice(0,6)}…${t.slice(-4)}` `` if you need diagnostic output.

## Overview

The query flow consists of:

1. **Generate X402 Access Token**: Get a payment-authorized token for agent access
2. **Make Authenticated Requests**: Include the token in HTTP headers
3. **Receive Responses**: Agent validates the token and processes the request

## Get X402 Access Token

The X402 access token is a cryptographically signed credential that proves you have purchased access to an agent:

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

// Initialize with subscriber's API key
const subscriberPayments = Payments.getInstance({
  nvmApiKey: process.env.SUBSCRIBER_API_KEY!,
  environment: 'sandbox' as EnvironmentName,
})

// Generate access token
const { accessToken } = await subscriberPayments.x402.getX402AccessToken(
  planId,   // Required: The plan you purchased
  agentId   // Optional: Specific agent ID to restrict access
)

console.log('Access token generated')
```

### Token Parameters

The `getX402AccessToken` method takes the plan id plus two optional arguments:

```typescript theme={null}
const { accessToken } = await subscriberPayments.x402.getX402AccessToken(
  planId,
  agentId,       // Optional: restrict the token to a specific agent
  tokenOptions,  // Optional: X402TokenOptions (scheme, network, delegationConfig)
)
```

Both schemes require `tokenOptions.delegationConfig` — pass
`{ delegationId }` for a delegation created via
[`createDelegation`](#card-delegation-tokens-fiat).

### Card-Delegation Tokens (Fiat)

For plans that accept fiat payments, use the `nvm:card-delegation` scheme.
Create the delegation once with `createDelegation` (passing the enrolled card's
`providerPaymentMethodId` and the required `currency`), then request tokens by
its `delegationId`:

```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. List enrolled payment methods and create a delegation once.
const methods = await subscriberPayments.delegation.listPaymentMethods()
console.log(`Found ${methods.length} enrolled card(s)`)

const { delegationId } = await subscriberPayments.delegation.createDelegation({
  provider: methods[0].provider ?? 'stripe',
  providerPaymentMethodId: methods[0].id, // or a specific 'pm_...' ID
  spendingLimitCents: 1000, // max $10.00
  durationSecs: 3600, // 1 hour delegation
  currency: 'usd',
})

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

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

#### Auto-Detecting the Scheme

If you don't know whether a plan uses crypto or fiat, use `resolveScheme()` to auto-detect from plan metadata:

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

const scheme = await resolveScheme(subscriberPayments, planId)

let tokenOptions: X402TokenOptions | undefined
if (scheme === 'nvm:card-delegation') {
  const methods = await subscriberPayments.delegation.listPaymentMethods()
  const { delegationId } = await subscriberPayments.delegation.createDelegation({
    provider: methods[0].provider ?? 'stripe',
    providerPaymentMethodId: methods[0].id,
    spendingLimitCents: 1000,
    durationSecs: 3600,
    currency: 'usd',
  })
  tokenOptions = {
    scheme: 'nvm:card-delegation',
    delegationConfig: { delegationId },
  }
}

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

#### CLI

> ⚠️ Inline create-on-the-fly is deprecated (nevermined-io/nvm-monorepo#1674) — the `--payment-type fiat` / `--payment-method-id` / `--spending-limit-cents` / `--delegation-duration-secs` flags create a delegation on the fly. Prefer creating a delegation first, then requesting the token by its `delegationId`.

```bash theme={null}
# Crypto (default)
nevermined x402token get-x402-access-token <planId>

# Fiat with auto-selected card
nevermined x402token get-x402-access-token <planId> --payment-type fiat

# Fiat with specific card and limits
nevermined x402token get-x402-access-token <planId> --payment-type fiat \
    --payment-method-id pm_1AbCdEfGhIjKlM \
    --spending-limit-cents 5000 \
    --delegation-duration-secs 7200

# Auto-detect scheme from plan metadata
nevermined x402token get-x402-access-token <planId> --auto-resolve-scheme

# List enrolled payment methods
nevermined delegation list-payment-methods
```

### Basic Example

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

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

// Simple token generation
const { accessToken } = await subscriberPayments.x402.getX402AccessToken(
  planId,
  agentId
)

// ⚠️ Never log the full token — it is a bearer credential.
console.log('Access token generated')
```

## Token Structure (X402 v2)

The access token is a JSON Web Token (JWT) containing an X402 v2 payment credential:

```json theme={null}
{
  "x402Version": 2,
  "accepted": {
    "scheme": "nvm:erc4337",
    "network": "eip155:84532",
    "planId": "plan-123",
    "extra": {
      "version": "1",
      "agentId": "did:nv:agent-456"
    }
  },
  "payload": {
    "signature": "0x...",
    "authorization": {
      "from": "0xSubscriberAddress",
      "sessionKeysProvider": "zerodev",
      "sessionKeys": []
    }
  },
  "extensions": {}
}
```

## Make Requests with X402 Token

### Using payment-signature Header (X402 v2 Spec)

The X402 v2 specification defines the `payment-signature` header for payment credentials:

```typescript theme={null}
// Make authenticated request to agent
const response = await fetch('https://agent.example.com/api/v1/tasks', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'payment-signature': accessToken,  // X402 v2 standard header
  },
  body: JSON.stringify({
    prompt: 'What is the weather in San Francisco?',
  }),
})

const result = await response.json()
console.log(result)
```

**Note**: The A2A (Agent-to-Agent) protocol also uses the `payment-signature` header for authentication. For A2A integration details, see the [A2A Integration](./a2a-integration) guide.

## Complete Query Example

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

async function queryAgent(
  planId: string,
  agentId: string,
  agentUrl: string,
  prompt: string
) {
  // Initialize subscriber payments
  const subscriberPayments = Payments.getInstance({
    nvmApiKey: process.env.SUBSCRIBER_API_KEY!,
    environment: 'sandbox' as EnvironmentName,
  })

  try {
    // 1. Generate access token
    const { accessToken } = await subscriberPayments.x402.getX402AccessToken(
      planId,
      agentId
    )
    console.log('✓ Access token generated')

    // 2. Make authenticated request
    const response = await fetch(`${agentUrl}/tasks`, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'payment-signature': accessToken,
      },
      body: JSON.stringify({ prompt }),
    })

    // 3. Handle response
    if (!response.ok) {
      if (response.status === 402) {
        console.error('Payment required - insufficient credits')
      } else {
        console.error(`Request failed: ${response.statusText}`)
      }
      return null
    }

    const result = await response.json()
    console.log('✓ Agent response received')
    return result

  } catch (error) {
    console.error('Failed to query agent:', error)
    return null
  }
}

// Usage
const result = await queryAgent(
  'plan-123',
  'did:nv:agent-456',
  'https://weather-agent.example.com/api/v1',
  'What is the weather forecast for tomorrow?'
)
```

## Handling 402 Payment Required

If the token is invalid or credits are insufficient, agents return HTTP 402 with payment details:

```typescript theme={null}
const response = await fetch(agentUrl, {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'payment-signature': accessToken,
  },
  body: JSON.stringify({ prompt }),
})

if (response.status === 402) {
  // Read PAYMENT-REQUIRED header
  const paymentRequiredHeader = response.headers.get('PAYMENT-REQUIRED')

  if (paymentRequiredHeader) {
    // Decode base64 payment required info
    const paymentRequired = JSON.parse(
      Buffer.from(paymentRequiredHeader, 'base64').toString()
    )

    console.log('Payment required:', paymentRequired)
    console.log(`Plan ID: ${paymentRequired.accepts[0].planId}`)

    // User needs to purchase plan or top up credits
  }
}
```

## MCP JSON-RPC Requests

For MCP-based agents, use JSON-RPC format:

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

const response = await fetch('https://mcp-agent.example.com/mcp', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'payment-signature': accessToken,
  },
  body: JSON.stringify({
    jsonrpc: '2.0',
    id: 1,
    method: 'tools/call',
    params: {
      name: 'get_weather',
      arguments: {
        city: 'San Francisco'
      }
    }
  }),
})

const result = await response.json()
console.log(result.result)
```

## Token Reuse

X402 access tokens can be reused for multiple requests until they expire or credits are exhausted:

```typescript theme={null}
// Generate token once
const { accessToken } = await subscriberPayments.x402.getX402AccessToken(
  planId,
  agentId
)

// Use for multiple requests
for (const city of ['San Francisco', 'New York', 'London']) {
  const response = await fetch(agentUrl, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'payment-signature': accessToken,  // Reuse same token
    },
    body: JSON.stringify({ prompt: `Weather in ${city}` }),
  })

  const result = await response.json()
  console.log(`${city}:`, result)
}
```

## Check Balance Before Querying

To avoid 402 errors, check your balance before making requests:

```typescript theme={null}
async function queryWithBalanceCheck(
  planId: string,
  agentId: string,
  agentUrl: string,
  prompt: string
) {
  const subscriberPayments = Payments.getInstance({
    nvmApiKey: process.env.SUBSCRIBER_API_KEY!,
    environment: 'sandbox',
  })

  // Check balance first
  const balance = await subscriberPayments.plans.getPlanBalance(planId)
  const availableCredits = BigInt(balance.balance)

  if (availableCredits === 0n) {
    console.error('No credits available - please purchase a plan')
    return null
  }

  console.log(`Available credits: ${availableCredits}`)

  // Generate token and query
  const { accessToken } = await subscriberPayments.x402.getX402AccessToken(
    planId,
    agentId
  )

  const response = await fetch(agentUrl, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'payment-signature': accessToken,
    },
    body: JSON.stringify({ prompt }),
  })

  return await response.json()
}
```

## Best Practices

1. **Token Caching**: Generate tokens once and reuse them for multiple requests
2. **Balance Checking**: Check balance before generating tokens
3. **Error Handling**: Always handle 402 Payment Required responses
4. **HTTPS Only**: Never send tokens over unencrypted HTTP
5. **Token Expiration**: Regenerate tokens if you receive 402 errors
6. **Header Standard**: Prefer `payment-signature` header (X402 v2 spec)

## Related Documentation

* [Payments and Balance](./payments-and-balance) - How to purchase plans and check credits
* [Validation of Requests](./validation-of-requests) - How agents validate tokens (for builders)
* [X402 Protocol](./x402) - Complete X402 specification

***

**Source References**:

* `src/x402/token.ts` (getX402AccessToken method)
* `tests/e2e/test_x402_e2e.test.ts` (lines 114-133, token generation)
* `tests/e2e/test_payments_e2e.test.ts` (MockAgentServer, lines 72-127)
