Semana agentic: x402 estrena un ciclo de vida de pago
Esta semana se mergearon tres cambios en x402 y todos atacan la misma premisa: que un pago es una request, una firma y una liquidacion.
La semana pasada el tema eran las restricciones. Caps de gasto, un estado de settlement no terminal, limites en la capa de infraestructura. Esta semana el tema es el tiempo. Todo cambio sustantivo mergeado entre el 21 y el 28 de agosto mueve alguna parte del pago fuera del round trip HTTP unico en el que vivia: antes del handler, despues del handler, o horas mas tarde, fuera de banda.
Eso es lo que pasa cuando un rail de pago deja de ser un primitivo de paywall y empieza a ser un sistema de pagos. Las releases que cargan la semana son @x402/core 2.24.0 en npm y x402 2.21.0 en PyPI, ambas publicadas el 27 de agosto. Para dimensionar: @x402/core registro 1.023.046 descargas de npm en los treinta dias hasta el 27 de agosto, frente a las 871.818 que citabamos una semana antes.
1. auth-capture v1.1 elimino el flag y ato al authorizer
El PR #3197 se mergeo el 25 de agosto y reescribio la especificacion del scheme auth-capture: 782 lineas agregadas, 215 eliminadas, dos archivos. El cliente de TypeScript y Go siguio el 27 de agosto en 30 archivos. Ambos estan marcados como breaking.
El diseno anterior elegia entre comportamiento de dos fases y de un solo disparo con un booleano, extra.autoCapture. Ese flag desaparecio. extra.paymentFlow es ahora el unico selector de flujo, y el scheme declara dos:
- Escrow (el default del scheme) — retener primero, finalizar despues del recurso. Sincrono y stateless:
settle(authorize), trabajo,settle(capture)osettle(void), respuesta. Asincrono y stateful: authorize, trabajo, persistirpaymentInfoen almacenamiento durable, responder, y luego capture, void o refund fuera de banda. - Authorization — sin retencion.
verify, trabajo,settle(charge), respuesta, conrefunddisponible mas tarde.
El cliente sigue firmando exactamente una vez. Que esa firma se convierta en un authorize o en un charge se deduce del flujo, no de una segunda decision. Y las llamadas posteriores del ciclo de vida son requests POST /settle normales con un payload.type de "capture", "void" o "refund": la spec deliberadamente no agrego un endpoint de facilitator.
La parte interesante es la autenticacion de esas llamadas posteriores. Cuando auditamos auth-capture en su forma v1.0, nada ataba la identidad del resource server al pago: un capture relayado por el facilitator no podia probarse como del servidor. v1.1 lo arregla en EVM hasheando un extra.receiverAuthorizer distinto de cero — con un policy opcional y un saltNonce provisto por el cliente — dentro de PaymentInfo.salt. Un pago cobrado no puede reapuntarse a otro authorizer despues del hecho.
La spec ademas nombra el modelo de confianza de forma explicita, con extra.operatorType:
// delegated (default) — el operator es una direccion que controla el
// facilitator. Con receiverAuthorizer distinto de cero, el facilitator
// relaya collect Y ciclo de vida, con una firma EIP-712 del authorizer
// que NO se verifica onchain. El servidor confia en el facilitator.
// custom — el operator es un contrato no confiable con wrappers
// authorize/charge permissionless. El facilitator relaya solo el collect;
// capture/void/refund van por el ABI propio del operator, fuera de banda.
// policy (reservado) — campos de wire especificados ahora para que un
// operator canonico futuro haga el chequeo del receiverAuthorizer onchain.
Vale la pena leer esa tercera entrada con calma. La spec esta admitiendo que el modo por defecto tiene una asuncion de confianza sin enforcement, y reservando el formato de wire para cerrarla mas adelante en vez de fingir que ya esta cerrada. Los facilitators anuncian que operators admiten en /supported, y relayar hacia un operator custom exige gas caps y verificacion de resultados — eventos del escrow, paymentState, movimientos de tokens — no solo una llamada de nivel superior exitosa.
receiverAuthorizer y policy se omiten ambos, lo que deja el salt sin binding. En el momento en que quieras el binding, estas en el formato de wire v1.1 con saltNonce, y las firmas por defecto del cliente ahora apuntan a las direcciones de escrow y collector de v1.1. Fijar v1.0 requiere un extra.authCaptureEscrow explicito.
2. settlement_pending dejo de ser problema del caller
El roundup de la semana pasada cubrio la llegada de settlement_pending: un resultado no terminal para una liquidacion que se broadcasteo pero cuyo receipt no pudo recuperarse. Nombrar el estado era la mitad facil. El PR #3214, mergeado el 25 de agosto en 94 archivos y 11.276 lineas agregadas, hizo la mitad dificil.
Introduce una interfaz PendingSettlementStore en Go, TypeScript y Python, indexada por un identificador determinista por payload: la firma EIP-3009 o Permit2 en EVM, el message hash en SVM. El store se escribe solo en el camino broadcast exitoso mas confirmacion fallida, se consulta antes de cualquier broadcast nuevo, y se limpia tanto en exito terminal como en fallo terminal. La implementacion por defecto es en memoria, con TTL de cinco minutos y pruning perezoso.
El resource server entonces reintenta un fallo settlement_pending exactamente una vez, con el payload identico, sin backoff y sin mutacion. En ese reintento, el mecanismo encuentra el hash de transaccion almacenado y reconcilia contra la transaccion que ya existe en vez de verificar y broadcastear una segunda. Cualquier otro resultado corta despues de la primera llamada.
Dos detalles hacen que esto sea mas que un loop de reintentos. Primero, el store es una interfaz y no un tipo concreto, porque un facilitator multi-instancia sin session affinity necesita un backend compartido — Redis es el ejemplo nombrado — y el default en memoria fallaria en silencio ahi. Segundo, la cobertura ahora abarca EVM exact (tanto EIP-3009 como Permit2), EVM upto, EVM batch-settlement, SVM exact y SVM upto; la actualizacion de documentacion extiende la garantia de solo-EVM a ambas familias.
El PR documenta su propia brecha, que es la parte que querriamos en todo cambio de protocolo: el camino de cache-hit de reconcilePendingDeposit en batch-settlement se saltea un chequeo de confirmacion de balance que el camino de cache-miss si hace, porque le falta el snapshot del estado del canal previo al broadcast. Declarado inline, en los tres lenguajes.
3. exact aprendio a liquidar antes de servir
El PR #3240, mergeado el 25 de agosto en 98 archivos, le da al scheme exact un segundo payment flow: upfront.
Por defecto exact usa el flujo authorization: verificar antes de que corra el handler, liquidar despues. Con upfront, la liquidacion ocurre antes de que el handler corra siquiera. El endpoint /settle del facilitator valida y compromete a la vez, y /verify nunca se llama. El cliente firma el mismo payload en ambos casos; lo unico que cambia es el orden del lado del servidor.
app.use(paymentMiddleware({
"GET /weather": {
accepts: [{
scheme: "exact",
price: "$0.001",
network: "eip155:84532",
payTo: evmAddress,
extra: { paymentFlow: "upfront" }, // liquidar, luego correr el handler
}],
},
}, resourceServer));
El caso que motiva el cambio en la documentacion es preciso: un handler de larga duracion en Solana, donde el blockhash de la transaccion firmada puede expirar antes de que el handler termine. Verificar, trabajar y liquidar es una carrera contra el block time. Liquidar primero elimina esa carrera y la reemplaza por otra: el comprador pago por trabajo que todavia no ocurrio.
Los defaults reflejan ese intercambio con honestidad. authorization sigue siendo el default, los clientes lo prefieren cuando se ofrecen ambos, los servidores optan por ruta, y el servidor senala el flujo resuelto de vuelta en extra.paymentFlow dentro de la respuesta 402. Los schemes upto y batch-settlement siguen declarando solo authorization.
Puestos lado a lado, los tres cambios tienen una forma clara. upfront mueve la liquidacion hacia adelante. Escrow mueve la finalizacion hacia atras. settlement_pending cubre el caso donde cae en el medio. Un protocolo de pago de un solo round trip tiene ahora tres respuestas distintas a "cuando se mueve el dinero".
4. MCP publico un roadmap y aprobo el charter de transportes
El 22 de agosto los mantenedores de MCP reemplazaron el roadmap de marzo por uno nuevo, firmado por los lead maintainers David Soria Parra y Den Delimarsky. Nombra cinco areas prioritarias: primitivos de mensajeria agentica, unificacion y hardening del transporte HTTP-nativo, identidad de agentes y seguridad lista para empresa, mejores primitivos, y mejor experiencia de desarrollo en los SDKs.
Los items concretos importan mas que los titulos. Eventos iniciados por el servidor — webhooks y channels — para que los clientes dejen de hacer polling. Madurar la extension Tasks (SEP-2663) hasta que pueda entrar a la especificacion. Extender Streamable HTTP hasta los servidores locales sobre stdio, para que el core sin estado de 2026-07-28 aplique en todos lados y no solo en remoto. Finalizar DPoP, implementar Workload Identity Federation, y seguir el trabajo conjunto con los working groups OAuth y WIMSE del IETF. Discovery progresivo para catalogos de tools, para que un cliente ya no tenga que cargar la superficie completa antes de que el usuario pueda actuar.
Dos notas de gobernanza faciles de pasar por alto. Enterprise-Managed Authorization figura ahora como estable. Y los SEPs que caen dentro de estas cinco areas reciben revision acelerada, lo que convierte al roadmap de una declaracion de intenciones en una tabla de ruteo para el esfuerzo de los contribuidores. Las fechas de release se omitieron a proposito.
Cuatro dias despues, el 26 de agosto, se mergeo el charter del Transports Working Group, liderado por Kurtis Van Gent. Dentro del alcance: bindings de transporte, ciclo de vida de conexion, multiplexing, garantias de entrega, operacion sin estado, y seguridad de transporte (TLS, mTLS, validacion de Origin) en conjunto con el Security Interest Group. Fuera del alcance, explicitamente: comportamiento de la capa de aplicacion, mecanica de autorizacion, internals de los SDKs, y la propiedad de la suite de conformidad. Los cambios aditivos a la spec requieren consenso del WG mas aprobacion de un Core Maintainer; los breaking requieren revision mas amplia.
5. Tambien se lanzo
Sei entro a la tabla de default assets de EVM el 24 de agosto con el PR #3227: USDC nativo en mainnet (eip155:1329) y testnet (eip155:1328), ambos verificados onchain como USDC de seis decimales version 2, con authorization state de EIP-3009 y domain separators EIP-712 coincidentes. El mismo PR corrigio el chain ID legacy de Sei Testnet en Python, de 713715 a 1328: un chain ID equivocado en un domain separator es una firma que no verifica en ningun lado, exactamente la clase de fallo que recorrimos en la auditoria de default assets.
En paralelo, el PR #3241 elimino mapas de red duplicados de los SDKs de Go y Python para alinear su declaracion de default assets con TypeScript: 48 archivos, 257 lineas agregadas y 1.163 eliminadas. El neto negativo es la direccion correcta para una tabla en la que tres lenguajes tienen que coincidir. La tabla de documentacion gano filas de Ethereum mainnet y Avalanche C-Chain el mismo dia, y Python recibio el port de payment flows el 24 de agosto. Fireblocks se agrego a la lista publicada de facilitators el 20 de agosto, descrito como open-source y hosteado, con liquidacion desde un vault de Fireblocks y llaves privadas que nunca salen de ahi.
Que significa para LLM4Agents
Los tres cambios de x402 no son igual de relevantes para un gateway de inferencia, y conviene ser preciso sobre cual es cual.
La auto-recuperacion de settlement_pending es la que heredamos gratis y deberiamos adoptar ya. Nuestro camino de facturacion reserva, proxea y liquida; un broadcast cuyo receipt no podemos leer es exactamente el fallo que convierte una llamada de inferencia en dos cargos. El reintento del lado del cliente ya esta en el SDK, pero el default de PendingSettlementStore es en memoria, y cualquier gateway que corra mas de una replica necesita la implementacion compartida. Eso es una decision de despliegue, no de codigo, y equivocarse reintroduce el bug que el PR fue escrito para eliminar.
El flujo upfront es el que mayormente deberiamos declinar. Liquidar antes de que corra el handler tiene sentido cuando el riesgo es el block time; para inferencia, el precio no se conoce hasta contar los tokens, que es la razon por la que existe el scheme upto y por la que upto sigue declarando solo authorization. Donde upfront si encaja es en endpoints auxiliares de precio fijo: una tool call, un lookup, una completion cacheada, servidos bajo exact.
auth-capture v1.1 es el que cambia lo que podemos ofrecer. Un ciclo authorize-luego-capture con un authorizer atado es la forma en que un gateway vende una sesion en vez de una request: retener un techo cuando el agente abre una conversacion, capturar el gasto real cuando la cierra, hacer void de la diferencia. El arbol de decision walk-up vs cuenta gana una tercera opcion: un agente walk-up que no necesita cuenta pero si necesita mas de una llamada. La salvedad es la firma sin enforcement del operator delegated: por ahora, correr ese modo significa confiar en que el facilitator envie exactamente lo que firmamos.
Como mantenerse en la frontera
Cuatro cosas, en orden.
Primero, reemplazar el pending-settlement store en memoria antes de habilitar cualquier otra cosa. Un PendingSettlementStore compartido y respaldado por red es prerrequisito para escalar horizontalmente el camino de liquidacion, y es un cambio chico que se vuelve caro si se descubre en produccion.
Segundo, prototipar el escrow de auth-capture v1.1 para inferencia con alcance de sesion. Autorizar un techo por sesion, capturar el gasto real de tokens al cerrar, hacer void del resto. Usar el operator delegated con un receiverAuthorizer explicito para que el ciclo de vida quede atado a nosotros, y seguir de cerca el operator type policy reservado: cuando un operator canonico haga el chequeo del authorizer onchain, ese es el dia en que la asuncion de confianza desaparece y deberiamos migrar en la misma semana.
Tercero, adoptar upfront de forma selectiva y decirlo en el 402. Solo endpoints de precio fijo, por ruta, dejando authorization como default para todo lo medido. El flujo se anuncia en extra.paymentFlow, asi que los compradores pueden ver el orden antes de firmar.
Cuarto, seguir el trabajo de eventos iniciados por el servidor de MCP ahora, no cuando salga. Webhooks y channels mas una extension Tasks madura es la diferencia entre un agente que hace polling a nuestro gateway por un trabajo largo y uno al que se le devuelve la llamada. Nuestro servidor MCP asume hoy el modelo de polling. Los SEPs dentro de las cinco areas del roadmap reciben revision acelerada, lo que significa que esto aterriza antes de lo que sugiere la ausencia de fechas publicadas.
Paga por inferencia, en stablecoins, sobre una API compatible con OpenAI
Settlement con x402 y EIP-3009, ruteo de modelos y fallback, sin suscripcion.
Registrar un agente