Protege un endpoint de API con x402: acepta pagos en USDC en tu servidor Node.js

Vender acceso a una API solía implicar crear cuentas, claves de API, un sistema de facturación y una integración con Stripe antes de poder cobrar un solo centavo. El protocolo x402 reduce todo eso a un único código de estado HTTP: tu servidor responde 402 Payment Required con un precio, el cliente paga en USDC y la misma petición se completa segundos después. Sin registro, sin claves de API, sin suscripciones y sin comisiones de protocolo.

En este tutorial vamos a construir el circuito completo, en los dos lados de la transacción:

  • Lado del vendedor: un servidor Express con un endpoint, GET /api/premium, protegido por un pago de 0,01 $ en USDC en Base.
  • Lado del comprador: un cliente JavaScript y un cliente Python que tienen una clave privada, detectan el 402, firman el pago y reintentan automáticamente.

Todo se ejecuta en Base Sepolia (testnet) con USDC de prueba gratuito, y terminamos con los cambios exactos que hacen falta para pasar a mainnet.

Cómo funciona x402 en un diagrama

x402 es un estándar abierto, creado en Coinbase y que ahora gestiona la x402 Foundation bajo el paraguas de la Linux Foundation. Pone a trabajar el código de estado 402 Payment Required, reservado desde hace mucho tiempo: los servidores anuncian un precio en un formato legible por máquinas, los clientes lo pagan con una autorización de stablecoin firmada y un tercer servicio, llamado facilitador, verifica y liquida el pago on-chain, de modo que tu servidor nunca habla con un nodo de blockchain.

secuencia de pago de x402: petición, 402, reintento firmado, verificación, liquidación, respuesta
El ciclo de vida completo de una petición x402. Las flechas continuas son peticiones; las discontinuas, respuestas.

Tres detalles hacen que este flujo destaque:

  • El comprador nunca gasta gas. El paso 3 es una firma off-chain (EIP-3009 transferWithAuthorization, que USDC admite de forma nativa). El facilitador envía la transacción y paga el gas.
  • Los fondos solo se mueven si el servidor entrega. La firma autoriza exactamente el importe anunciado, y la liquidación ocurre después de que se ejecute tu handler (paso 7). No hay nada que reembolsar ni ningún contracargo posible.
  • El facilitador no custodia los fondos. Ejecuta payloads firmados; no puede cambiar el importe ni desviar los fondos.

Qué vamos a construir

arquitectura de red de x402: cliente comprador y wallet, servidor Express con middleware x402, facilitador y el contrato de USDC en Base
Las cuatro piezas en juego: un script comprador con una hot wallet, tu servidor Express, un facilitador y USDC en Base.

El lado del vendedor es tu API actual más un middleware. El lado del comprador es cualquier cliente HTTP envuelto con un interceptor x402 y una wallet. El facilitador (el público de x402.org en testnet; Coinbase CDP u otro proveedor en mainnet) se sitúa entre tu servidor y la cadena.

Requisitos previos

  • Node.js 20+ y npm (o yarn)
  • Python 3.10+ para el comprador en Python
  • Dos direcciones EVM: una para recibir fondos (vendedor; basta con la dirección, no hace falta ninguna clave privada en el servidor) y otra para pagar (comprador; la clave privada es necesaria)
  • USDC de prueba en Base Sepolia para el comprador, gratis desde el faucet de Circle

Si necesitas claves nuevas, genera una wallet desechable en local:

generate-wallet.mjs
import { generatePrivateKey, privateKeyToAccount } from 'viem/accounts'

const privateKey = generatePrivateKey()
const account = privateKeyToAccount(privateKey)

console.log('Address:     ', account.address)
console.log('Private key: ', privateKey)

Ejecútalo con node generate-wallet.mjs después de npm install viem. Mantén la clave privada fuera del historial de tu shell y de tu repositorio git; más adelante la cargaremos desde una variable de entorno. Fondea la dirección del comprador con USDC de prueba desde el faucet (selecciona "Base Sepolia"). El comprador no necesita nada de ETH: los pagos no consumen gas para ninguna de las dos partes.

Parte 1: proteger el endpoint (lado del vendedor)

Crea el proyecto del servidor e instala los paquetes de x402:

mkdir x402-server && cd x402-server npm init -y && npm pkg set type=module npm install express @x402/express @x402/core @x402/evm

La configuración del vendedor se reduce a una única variable de entorno: la dirección que recibe el USDC.

.env
PAY_TO_ADDRESS=0xYourSellerAddress

Y ahora, el servidor completo:

server.js
import express from 'express'
import { paymentMiddleware, x402ResourceServer } from '@x402/express'
import { ExactEvmScheme } from '@x402/evm/exact/server'
import { HTTPFacilitatorClient } from '@x402/core/server'

const payTo = process.env.PAY_TO_ADDRESS
if (!payTo) throw new Error('PAY_TO_ADDRESS not configured')

// Public facilitator, testnet only. Swap for a mainnet facilitator in production.
const facilitatorClient = new HTTPFacilitatorClient({
  url: 'https://x402.org/facilitator',
})

// Registers which payment scheme we accept on which network.
const resourceServer = new x402ResourceServer(facilitatorClient).register(
  'eip155:84532', // Base Sepolia
  new ExactEvmScheme(),
)

const app = express()

app.use(
  paymentMiddleware(
    {
      'GET /api/premium': {
        accepts: [
          {
            scheme: 'exact',
            price: '$0.01',
            network: 'eip155:84532',
            payTo,
          },
        ],
        description: 'Premium market report, paid per request',
        mimeType: 'application/json',
      },
    },
    resourceServer,
  ),
)

app.get('/api/premium', (req, res) => {
  res.json({
    report: 'Institutional flows turned net positive this week.',
    generatedAt: new Date().toISOString(),
  })
})

app.get('/api/free', (req, res) => {
  res.json({ status: 'ok' }) // Routes not listed in the middleware stay free.
})

app.listen(4021, () => console.log('Listening on http://localhost:4021'))

Veamos las piezas una por una:

  • HTTPFacilitatorClient apunta al facilitador que verificará y liquidará los pagos. https://x402.org/facilitator es gratuito y admite Base Sepolia, lo que lo hace perfecto para desarrollo.
  • x402ResourceServer.register(...) vincula un esquema de pago a una red. El esquema exact significa precio fijo: el comprador firma exactamente por el importe anunciado. Las redes usan identificadores CAIP-2, así que eip155:84532 es Base Sepolia y eip155:8453 es la mainnet de Base.
  • paymentMiddleware asocia patrones de ruta con sus requisitos de pago. price: '$0.01' es un importe en dólares; el middleware lo traduce a unidades atómicas de USDC (10.000, ya que USDC tiene 6 decimales). Solo se protegen las rutas que enumeras.
  • El handler de la ruta no cambia en absoluto. Cuando se ejecuta, el pago ya se ha verificado.

Arráncalo y prueba el endpoint sin pagar:

node --env-file=.env server.js curl -i http://localhost:4021/api/premium

Recibes un 402 y una oferta legible por máquinas (aquí recortada):

cuerpo de la respuesta 402
{
  "x402Version": 2,
  "error": "Payment required",
  "accepts": [
    {
      "scheme": "exact",
      "network": "eip155:84532",
      "maxAmountRequired": "10000",
      "asset": "0x036CbD53842c5426634e7929541eC2318f3dCF7e",
      "payTo": "0xYourSellerAddress",
      "resource": "http://localhost:4021/api/premium",
      "description": "Premium market report, paid per request",
      "mimeType": "application/json",
      "maxTimeoutSeconds": 60,
      "extra": { "name": "USDC", "version": "2" }
    }
  ]
}

Ese array accepts es el corazón del protocolo: contiene todo lo que un comprador necesita para construir un pago válido, incluidas la dirección del contrato de USDC (asset) y tu dirección de recepción (payTo). Tu endpoint ya está monetizado. Nadie puede llamarlo sin pagar, y no has escrito ni una línea de código de facturación.

Parte 2: pagar el endpoint desde JavaScript (lado del comprador)

El comprador envuelve un fetch estándar con un interceptor que gestiona todo el baile del 402 de forma transparente. En un proyecto aparte:

mkdir x402-buyer && cd x402-buyer npm init -y && npm pkg set type=module npm install @x402/fetch @x402/core @x402/evm viem

Pásale al cliente la clave privada del comprador a través del entorno, nunca en el código:

.env
EVM_PRIVATE_KEY=0xYourBuyerPrivateKey
client.mjs
import { wrapFetchWithPayment, x402HTTPClient } from '@x402/fetch'
import { x402Client } from '@x402/core/client'
import { ExactEvmScheme } from '@x402/evm/exact/client'
import { privateKeyToAccount } from 'viem/accounts'

const privateKey = process.env.EVM_PRIVATE_KEY
if (!privateKey) throw new Error('EVM_PRIVATE_KEY not configured')

// The signer that will authorize USDC transfers.
const signer = privateKeyToAccount(privateKey)

// Register the exact scheme for every EVM network (eip155:*).
const client = new x402Client()
client.register('eip155:*', new ExactEvmScheme(signer))

// A drop-in fetch that pays 402s automatically.
const fetchWithPayment = wrapFetchWithPayment(fetch, client)

const response = await fetchWithPayment('http://localhost:4021/api/premium')
const data = await response.json()
console.log('Body:', data)

// The settlement receipt travels back in the PAYMENT-RESPONSE header.
const receipt = new x402HTTPClient(client).getPaymentSettleResponse((name) =>
  response.headers.get(name),
)
console.log('Paid on', receipt.network, '- tx:', receipt.transaction)

Ejecútalo:

node --env-file=.env client.mjs
Body: { report: 'Institutional flows turned net positive this week.', generatedAt: '2026-07-10T09:14:52.113Z' } Paid on eip155:84532 - tx: 0x6e1f...c40b

Por debajo, wrapFetchWithPayment hizo la primera petición, recibió el 402, eligió una opción de pago que podía cumplir, firmó la autorización EIP-3009 con tu clave, reintentó con la cabecera PAYMENT-SIGNATURE y te entregó el 200 final. El hash de transacción del recibo corresponde a una transferencia real que puedes consultar en Sepolia Basescan.

Existe un paquete equivalente, @x402/axios, si tu código base usa interceptores de axios en lugar de fetch.

Parte 3: el mismo comprador en Python

Los agentes de IA son los compradores naturales de las API protegidas con x402, y buena parte de ese ecosistema vive en Python. El paquete x402 replica el flujo de JavaScript con un cliente httpx:

pip install "x402[httpx]" eth-account python-dotenv
buyer.py
import asyncio
import os

from dotenv import load_dotenv
from eth_account import Account
from x402 import x402Client
from x402.http import x402HTTPClient
from x402.http.clients import x402HttpxClient
from x402.mechanisms.evm import EthAccountSigner
from x402.mechanisms.evm.exact.register import register_exact_evm_client

load_dotenv()

private_key = os.getenv("EVM_PRIVATE_KEY")
if not private_key:
    raise RuntimeError("EVM_PRIVATE_KEY not configured")

account = Account.from_key(private_key)

client = x402Client()
register_exact_evm_client(client, EthAccountSigner(account))


async def main() -> None:
    async with x402HttpxClient(client) as http:
        response = await http.get("http://localhost:4021/api/premium")
        print("Body:", response.json())

        receipt = x402HTTPClient(client).get_payment_settle_response(
            lambda name: response.headers.get(name)
        )
        print("Paid on", receipt.network, "- tx:", receipt.transaction)


asyncio.run(main())

Ejecuta python buyer.py y obtendrás la misma respuesta pagada y el mismo recibo de liquidación. La estructura es idéntica a la del cliente JavaScript: crea un firmante a partir de la clave privada, registra el esquema EVM exact y deja que el cliente HTTP envuelto absorba el handshake del 402.

Pasar a mainnet

Tres cambios bastan para llevar esto a producción:

  1. Red: sustituye eip155:84532 por eip155:8453 (mainnet de Base) tanto en la configuración del middleware como en el registro del resource server. El USDC de mainnet en Base está en 0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913; el SDK lo resuelve por ti.
  2. Facilitador: el facilitador de x402.org solo funciona en testnet. Apunta HTTPFacilitatorClient a un facilitador de producción como Coinbase CDP (https://api.cdp.coinbase.com/platform/v2/x402) u otro proveedor del directorio de facilitadores.
  3. Fondos: la wallet del comprador ahora necesita USDC real en Base, y tu dirección payTo recibe ingresos reales, de forma instantánea y definitiva.

También puedes registrar varias redes a la vez (Base y Solana, por ejemplo) y dejar que cada comprador pague en la cadena que prefiera: el array accepts simplemente enumera más opciones.

Notas de seguridad que no deberías saltarte

  • La clave privada del comprador es el único secreto de todo el sistema. Cárgala desde una variable de entorno o un gestor de secretos, nunca la subas al repositorio y nunca la escribas en los logs. Usa una hot wallet dedicada que solo contenga un saldo para gastos (unos pocos dólares en USDC), no tu tesorería; la clave está en una máquina que hace pagos automáticos, así que da por hecho que puede filtrarse y limita el alcance de los daños.
  • El vendedor no guarda ningún secreto. El servidor solo conoce tu dirección pública de recepción. No hay ninguna clave que rotar ni nada que un atacante pueda robar; para ingresos reales, plantéate usar una hardware wallet o una wallet multisig como payTo.
  • Los importes están acotados por diseño. Una autorización EIP-3009 es válida para un importe, un destinatario y una ventana de tiempo concretos, con un nonce único, así que no puede repetirse ni inflarse. Además, los clientes pueden limitar en la configuración del SDK lo que están dispuestos a pagar por petición.
  • Mantén la barrera delante de todo lo que sea de pago. El middleware solo protege las rutas que enumeras; un refactor que renombra una ruta pero no la configuración del middleware la vuelve gratuita sin avisar. Añade un test que compruebe que las peticiones sin pagar reciben un 402.

Donde esto se pone interesante

Un precio en un endpoint HTTP es una primitiva pequeña con grandes consecuencias. Significa que un agente de IA puede comprar un conjunto de datos en mitad de una tarea sin que una persona tenga que completar un formulario de tarjeta; significa que tu microservicio interno puede abrirse al mundo como producto en una tarde; significa que se puede vender contenido por artículo a lectores anónimos de cualquier país. Explicamos los conceptos con más detalle en nuestra página del servicio x402, incluidos los casos de uso que vemos funcionar hoy. ¿No sabes cuánto cobrar? Nuestra calculadora de precios x402 gratuita sugiere un precio por petición a partir de tu costo y tu margen objetivo, y compara las comisiones con las de Stripe.

En Etherwave Labs integramos x402 de principio a fin: protegemos tu API y definimos sus precios, conectamos facilitadores de producción y equipamos a tus agentes con wallets de gasto seguras. Si quieres una API con pagos nativos en producción, contáctanos.

Más artículos

¿Quieres llevar tu proyecto al siguiente nivel?

Contáctanos hoy para ver cómo podemos ayudarte a alcanzar tus objetivos en el sector blockchain.