Skip to main content
Start here: need to register a service and create a plan first? Follow the 5-minute setup.
Generic patterns for integrating Nevermined payments into any HTTP server or framework.

The x402 Payment Flow

When using x402, the client typically doesn’t start with a token. Instead, the server advertises payment requirements via 402 Payment Required, and the client retries with a payment proof.

Implementation Steps

1. Extract the x402 token from the request

x402 clients send the payment token in the payment-signature header (lowercase, per x402 v2 spec):
payment-signature: <x402_access_token>

2. Return 402 if token is missing

When no token is provided, return HTTP 402 with a base64-encoded payment-required header:
import { Payments, buildPaymentRequired } from '@nevermined-io/payments'

const PLAN_ID = process.env.NVM_PLAN_ID!
const AGENT_ID = process.env.NVM_AGENT_ID

// Build the payment required object
const paymentRequired = buildPaymentRequired(PLAN_ID, {
  endpoint: req.path,
  agentId: AGENT_ID,
  httpVerb: req.method
})

// Check for token
const token = req.headers['payment-signature']
if (!token) {
  const paymentRequiredBase64 = Buffer.from(
    JSON.stringify(paymentRequired)
  ).toString('base64')

  return res
    .status(402)
    .setHeader('payment-required', paymentRequiredBase64)
    .json({ error: 'Payment Required', message: 'Missing x402 access token' })
}

3. Verify permissions with the Facilitator

Before processing the request, verify the subscriber has sufficient credits:
const payments = Payments.getInstance({
  nvmApiKey: process.env.NVM_API_KEY!,
  environment: 'sandbox'
})

const verification = await payments.facilitator.verifyPermissions({
  paymentRequired,
  x402AccessToken: token,
  maxAmount: BigInt(creditsRequired)  // e.g., 1n
})

if (!verification.isValid) {
  const paymentRequiredBase64 = Buffer.from(
    JSON.stringify(paymentRequired)
  ).toString('base64')

  return res
    .status(402)
    .setHeader('payment-required', paymentRequiredBase64)
    .json({ error: 'Payment Required', message: verification.invalidReason })
}

// Verification passed - process the request

4. Process the request

Execute your business logic after verification passes.

5. Settle (burn credits) after successful response

After the request completes successfully, settle the credits and include the receipt in the response:
// After processing the request successfully...
const settlement = await payments.facilitator.settlePermissions({
  paymentRequired,
  x402AccessToken: token,
  maxAmount: BigInt(creditsUsed)
})

// Include settlement receipt in response header
const settlementBase64 = Buffer.from(JSON.stringify(settlement)).toString('base64')

return res
  .setHeader('payment-response', settlementBase64)
  .json({ result: yourResponseData })

x402 Headers Summary

HeaderDirectionDescription
payment-signatureClient → Serverx402 access token
payment-requiredServer → Client (402)Base64-encoded payment requirements
payment-responseServer → Client (200)Base64-encoded settlement receipt

HTTP Response Codes

CodeMeaningWhen to Use
200SuccessValid payment proof, request processed
402Payment RequiredMissing/invalid payment proof, insufficient credits
500Server ErrorValidation system failure
For Express.js and FastAPI, use the built-in middleware that handles the entire x402 flow automatically:
import { paymentMiddleware } from '@nevermined-io/payments/express'

app.use(paymentMiddleware(payments, {
  'POST /ask': { planId: PLAN_ID, credits: 1 }
}))
See Express.js Integration for details.

Best Practices

For high-traffic endpoints, consider caching validation results briefly (5-30 seconds) to reduce API calls.
Set reasonable timeouts for validation calls (5-10 seconds) and have a fallback strategy.
Log all payment validations for debugging and analytics: - Token hash (not full token) - Validation result - Credits consumed - Timestamp
Always include plan information in 402 responses so clients know how to get access.

Security Considerations

  1. Never log full tokens - Hash them if you need to identify requests
  2. Use HTTPS - Tokens should only travel over encrypted connections
  3. Validate on server - Never trust client-side validation
  4. Set token expiration - Accept reasonable token ages

Next Steps