← Blog
26 de julio, 2026 · 10 min

El seller stack de x402: cómo una ruta se convierte en endpoint pago

Hace dos días recorrimos el buyer stack de x402 — el cliente que ve un 402, firma y reintenta. Esto es la imagen espejo: el seller stack, el código que decide que una ruta cuesta dinero, habla el handshake del 402 y solo hace el trabajo cuando el pago verifica. Son cuatro paquetes de middleware alrededor de una abstracción central, y las decisiones de diseño de ese núcleo determinan quién asume el riesgo cuando el settlement falla.

El material sale del mismo release v2.19.0 de los SDKs de TypeScript (publicado el 17 de julio de 2026) que usamos para el deep dive del buyer stack: el monorepo x402-foundation/x402 (Apache 2.0), el quickstart oficial para sellers, y los READMEs y el código fuente bajo typescript/packages/http. Todo lo que sigue es lo que se distribuye hoy, no roadmap.

Tres capas entre tu handler y la chain

El seller stack es deliberadamente aburrido en los bordes e interesante en el medio. En el borde hay un adapter delgado por framework — @x402/express, @x402/hono, @x402/next o @x402/fastify — que sabe leer headers y paths de su framework. Cada adapter implementa la misma interfaz HTTPAdapter de @x402/core: getHeader, getMethod, getPath, getAcceptHeader, getUserAgent. Esa es toda la superficie específica del framework.

Debajo del adapter está x402HTTPResourceServer, dueño de la tabla de rutas y de la gramática HTTP del protocolo — los headers PAYMENT-REQUIRED y PAYMENT-SIGNATURE que mapeamos en el post del facilitator. Y debajo está x402ResourceServer, el núcleo agnóstico al transporte: mantiene los schemes registrados por red y el cliente que habla con los endpoints /verify y /settle del facilitator. El seller nunca toca una chain directamente. El cableado es corto:

import { paymentMiddleware, x402ResourceServer } from "@x402/express";
import { ExactEvmScheme } from "@x402/evm/exact/server";
import { HTTPFacilitatorClient } from "@x402/core/server";

const facilitator = new HTTPFacilitatorClient({ url: "https://x402.org/facilitator" });
const server = new x402ResourceServer(facilitator)
  .register("eip155:84532", new ExactEvmScheme());

app.use(paymentMiddleware(routes, server));

Un detalle pesa más de lo que parece: el quinto parámetro del middleware, syncFacilitatorOnStart, es true por defecto. En el arranque el resource server llama al GET /supported del facilitator y aprende qué pares scheme–red puede liquidar de verdad. Tu tabla de rutas es una afirmación; la sincronización con el facilitator es la comprobación. Una ruta cotizada en una red que tu facilitator no puede liquidar es inventario muerto, y el SDK lo hace visible en el boot en vez de en el primer settlement fallido.

La tabla de rutas es la lista de precios

Todo lo que el seller cobra vive en un objeto declarativo. Las claves son método más patrón, con wildcards; los valores dicen qué pago desbloquea la ruta:

const routes = {
  "GET /api/premium/*": {
    accepts: [
      { scheme: "exact", price: "$0.05", network: "eip155:8453", payTo: evmAddress },
      { scheme: "exact", price: "$0.05",
        network: "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp", payTo: svmAddress },
    ],
    description: "Premium API access",
    mimeType: "application/json",
  },
};

accepts toma una entrada o un array. Un array significa que la misma ruta es pagable en varios rails a la vez — USDC en Base o en Solana, al precio que el seller elija en cada uno — y el cliente del buyer elige el que coincida con sus schemes registrados. Es la contraparte servidor del registro por patrones CAIP-2 del buyer: el seller publica opciones, el buyer las interseca con sus wallets. payTo vive dentro de cada entrada, así que rutas distintas — o rails distintos de la misma ruta — pueden pagar a direcciones distintas. maxTimeoutSeconds acota cuánto dura la oferta. Los precios aceptan la forma dólar "$0.10" o unidades atómicas crudas.

El campo scheme acepta la trilogía completa que cubrimos en posts previos: exact para precios fijos, upto para autorización medida en EVM, y batch-settlement para acumulación de alta frecuencia. Misma tabla de rutas, tres semánticas de settlement.

El ciclo del request, y quién carga el riesgo

Según el README de @x402/express, el middleware hace seis cosas en orden: matchea la ruta, busca el header de pago, devuelve un 402 con PAYMENT-REQUIRED si falta o es inválido, verifica el pago vía facilitator si está presente, deja correr tu handler, y liquida después de una respuesta exitosa.

Vuelve a leer la última cláusula. La verificación ocurre antes de tu handler; el settlement ocurre después. El orden es correcto — no quieres cobrar por un request al que tu handler luego responde con un 500 — pero mueve el riesgo hacia el seller. Entre /verify y /settle el seller ya hizo el trabajo sosteniendo solo una autorización firmada, no dinero. Si el settlement después falla — caída del facilitator, autorización expirada a mitad del request, congestión en la chain — el cómputo se gastó y el pago no llegó. En el post del facilitator señalamos el riesgo espejo (un success falso en el settle); esta es la versión honesta de la misma ventana. Para rutas de fracciones de centavo la exposición es ruido. Para una ruta cotizada en dólares por llamada, es una línea de conciliación que deberías estar registrando — que es exactamente para lo que existen los hooks.

Hooks: la superficie de auditoría

El resource server expone cuatro lifecycle hooks — onBeforeVerify, onAfterVerify, onBeforeSettle, onAfterSettle — los gemelos del lado seller de los hooks de cliente que cubrimos en el buyer. Ahí vive la política sin forkear el middleware: rechazar payers de una denylist antes de gastar un round-trip al facilitator, escribir el resultado del verify en tu audit log y, crítico, registrar cada resultado de settle con su hash de transacción para que los settlements fallidos se vuelvan cuentas por cobrar recuperables en vez de pérdidas silenciosas.

El cliente del facilitator también toma auth: HTTPFacilitatorClient acepta un callback createAuthHeaders que devuelve sets de headers separados para verify y settle. Esa separación es deliberada. Verify es un pre-flight tipo lectura que podrías delegar ampliamente; settle mueve dinero y puede llevar credenciales más estrictas. Los facilitators comerciales — el endpoint de CDP en api.cdp.coinbase.com/platform/v2/x402, PayAI, el resto del directorio que relevamos — se autentican exactamente ahí. El quickstart es directo con el otro footgun: x402.org/facilitator es solo testnet (Base Sepolia, Solana devnet). No apuntes rutas de mainnet ahí.

El billing medido es una llamada a función

El lado servidor del scheme upto es casi anticlimático. La ruta anuncia un máximo; el buyer firma una autorización por ese tope; tu handler mide el uso real y, antes de responder, escribe el monto verdadero:

import { setSettlementOverrides } from "@x402/express";

app.post("/api/generate", async (req, res) => {
  const out = await generate(req.body);
  // cobrar por lo consumido de verdad, no por el tope
  setSettlementOverrides(res, { amount: String(out.tokensUsed * PRICE_PER_TOKEN) });
  res.json(out);
});

El override acepta tres formatos: unidades atómicas crudas ("1000"), un porcentaje del tope autorizado ("50%"), o un monto en dólares ("$0.05", solo cuando la ruta misma se cotizó en dólares). El middleware recoge el override al momento del settle y pasa el monto real al facilitator — el flujo settle(permit, actualAmount) que trazamos por Permit2 en el deep dive de upto, ahora visible como un API de seller de una línea. La misma función la exporta el middleware de Fastify y está espejada en el SDK de Go, así que el patrón no es una rareza de Express.

Los humanos golpean el mismo 402

Un endpoint protegido tarde o temprano se abre en un navegador, y un navegador no puede firmar una autorización EIP-3009 por sí solo. El middleware lo resuelve con content negotiation: los agentes reciben el 402 legible por máquina, los navegadores reciben un paywall. Hay tres niveles. Con el paquete opcional @x402/paywall instalado, el seller obtiene una UI de pago completa — wallets EVM (MetaMask, Coinbase Wallet), wallets Solana (Phantom, Solflare), chequeo de balance USDC, cambio de chain y onramp integrado en mainnet. Sin él, el middleware cae a una página HTML básica con instrucciones de pago. Y una interfaz PaywallProvider permite reemplazar todo por tu propia UI.

Este es un punto estratégico silencioso. La misma tabla de rutas atiende al buyer máquina walk-up y al humano que abrió un link compartido, sin integración de checkout aparte. El paywall no es una feature de producto de un seller particular; es un default del rail.

Tools MCP como endpoints pagos

El seller stack no termina en rutas HTTP. @x402/mcp — la mitad servidor del paquete cuyo lado cliente cerró el post del buyer — envuelve handlers individuales de tools MCP en enforcement de pago:

const accepts = await server.buildPaymentRequirements({
  scheme: "exact", network: "eip155:84532", payTo: "0x...", price: "$0.10",
});
const paid = createPaymentWrapper(server, { accepts });

mcpServer.tool("financial_analysis", "Costs $0.10.", { ticker: z.string() },
  paid(async (args) => ({ content: [{ type: "text", text: await analyze(args.ticker) }] })));

Las tools gratis se registran normal; las pagas toman el wrapper. La granularidad de precio es por tool, no por servidor — un ping de health-check y un análisis de diez centavos conviven en el mismo proceso. Los hooks del wrapper codifican una regla que vale la pena robar: onBeforeExecution corre después de la verificación pero antes de que la tool ejecute, y devolver false aborta la llamada sin cobrar. Rate limiting, chequeos de cuota y filtros de abuso encajan ahí — negar el servicio, no tomar el dinero. onAfterSettlement dispara con el hash de transacción para recibos. Es la misma columna verify → trabajo → settle del middleware HTTP, trasplantada a llamadas de tools.

Un campo más cierra el loop con el discovery: las extensions de ruta aceptan la metadata de declareDiscoveryExtension que alimenta el índice del Bazaar. Declarar un input schema junto al precio es lo que convierte un endpoint pago de algo que hay que contarle a los agentes en algo que los agentes encuentran.

Qué significa para LLM4Agents

LLM4Agents está en ambos lados de este stack, y el lado seller es el que operamos en producción. Nuestro pipeline de billing reserve → proxy → settle es, estructuralmente, la misma columna que paymentMiddleware: verificar capacidad antes de la llamada al modelo, hacer el trabajo, liquidar el monto verdadero después — y nuestro settlement medido es la misma idea que setSettlementOverrides distribuye como API pública. Esa convergencia es validación, y también es commoditización: cualquier equipo con Express está ahora a cinco imports del flujo x402 walk-up que nosotros cobramos. La diferencia durable no es el middleware; es lo que hay detrás de la ruta — 345+ modelos, fallback chains, workspace y memoria — y la madurez operativa alrededor de la ventana de fallo del settle que el SDK deja como ejercicio.

En concreto, el stack nos da tres cosas. Primero, un objetivo de conformidad: nuestra superficie x402 walk-up debería comportarse byte a byte como un resource server v2.19.0, porque contra eso se testean los SDKs de buyer. Segundo, el payment wrapper de MCP importa para nuestro MCP server de 67 tools — precio por tool con semántica de abortar-sin-cobrar es exactamente el modelo de enforcement que un catálogo de tools necesita. Tercero, el nivel de paywall significa que la brecha entre "pagable por agente" y "pagable por humano" se está cerrando desde el lado seller; nuestros endpoints deberían asumir ambas audiencias en cada ruta.

Cómo mantenerse en la frontera

Ordenado por leverage. Primero, correr conformidad contra la referencia: levantar un servidor @x402/express desde el quickstart y disparar contra él nuestro propio cliente buyer y nuestro flujo walk-up en CI, fijado a cada release del SDK, para que la deriva en headers o formas de error aparezca la semana en que se publica y no en un reporte de cliente. Segundo, instrumentar la ventana de fallo del settle en nuestro propio pipeline — cada verify que no es seguido por un settle exitoso se vuelve una cuenta por cobrar registrada con payer, monto y razón; ese reporte es la diferencia entre un rail y una fuga. Tercero, adoptar el patrón del payment wrapper en la superficie MCP: precios por tool, chequeos de cuota en onBeforeExecution que abortan sin cobrar, recibos desde onAfterSettlement. Cuarto, publicar metadata de declareDiscoveryExtension en cada ruta con precio para que los agentes que rastrean el Bazaar nos encuentren sin trabajo de integración. Quinto, vigilar los SDKs de seller de Fastify y Go por rezago de features contra Express — el centro de gravedad del ecosistema se ve en qué middleware recibe primero features clase setSettlementOverrides, y eso nos dice de dónde vendrá el tráfico de buyers.

Véndele a agentes sin operar la plomería

LLM4Agents corre la columna verify–settle en producción — 345+ modelos detrás de un gateway pagable por x402.

Registra tu agente