Pagos x402 2026 v2: implementar y verificar la liquidación
Práctica con Node.js para añadir micropagos a una API con x402 v2. Selecciona las condiciones de pago, vuelve a solicitar la firma y verifica la liquidación en Base Sepolia. Revisa el reenvío y las condiciones para pasar a la red principal.
- Prepara la dirección del destinatario y la cartera para los pagos de prueba e instala el SDK oficial de x402.
- Conecta el middleware de pagos para Base Sepolia y comprueba la respuesta 402 a una solicitud sin pago.
- Selecciona y firma solo las condiciones que coincidan con la cadena, el token, el importe y el destinatario permitidos por el cliente.
- Consulta los eventos USDC Transfer con el hash de la transacción de la respuesta de liquidación.
- Prueba el bloqueo ante fallos y la recuperación de solicitudes duplicadas antes de revisar la configuración de la red principal.
Los pagos x402 se implementan incluyendo las condiciones de pago en la respuesta 402 de la API. Prepare Node.js y una cartera de prueba. Primero, verifique la firma y la liquidación de v2 en Base Sepolia. Configure la entrega de la respuesta de pago para que solo se envíe después de una liquidación correcta.
La información sobre importes y cadenas se basa en la documentación oficial de x402, Base y Circle enlazada como fuente.
Preparación e instalación para la práctica
Prepare un entorno de desarrollo donde pueda modificar la API y una cartera de prueba. El ejemplo está preparado para Node.js 22 y x402 SDK 2.28.0. La estructura de instalación sigue la guía oficial para vendedores.
- Prepare una dirección de cartera EVM para recibir los pagos.
- Prepare otra cartera de prueba para hacer los pagos.
- Consiga USDC de prueba de Base Sepolia para la cartera de pago.
- Cree el proyecto de práctica con los siguientes comandos.
- Guarde los archivos TypeScript que aparecen más adelante en la misma carpeta.
mkdir x402-demo
cd x402-demo
npm init -y
npm pkg set type=module
npm install --save-exact [email protected] [email protected] @x402/[email protected] @x402/[email protected] @x402/[email protected] @x402/[email protected]
npm install --save-dev --save-exact typescript tsx @types/node @types/express
El servidor receptor no necesita la clave privada de la cartera receptora. Configure la clave privada de pago para que solo se lea desde el proceso del cliente. El método de firma con la cartera se basa en la guía oficial para compradores.
La validación de este ejemplo se limita a la comprobación de tipos y a un flujo de pago simulado. No es un ejemplo en el que se haya completado una transferencia real en la red de prueba. Compruebe los resultados en la cadena durante el procedimiento de ejecución que se indica a continuación.
Comparación entre x402 v1 y v2
Al implementar v2, debe adaptar tanto las cabeceras como los campos del cuerpo. Cambiar solo los nombres de las cabeceras deja una estructura de datos incompatible. La siguiente tabla se basa en la guía oficial de migración.
| Aspecto | v1 | v2 |
|---|---|---|
| Versión del protocolo | x402Version: 1 |
x402Version: 2 |
| Condiciones de pago iniciales | Cuerpo JSON de la respuesta 402 | Cabecera de respuesta PAYMENT-REQUIRED
|
| Datos de pago firmados | Cabecera de solicitud X-PAYMENT
|
Cabecera de solicitud PAYMENT-SIGNATURE
|
| Resultado de la liquidación | Cabecera de respuesta X-PAYMENT-RESPONSE
|
Cabecera de respuesta PAYMENT-RESPONSE
|
| Identificador de la red principal de Base | base |
eip155:8453 |
| Identificador de Base Sepolia | base-sepolia |
eip155:84532 |
| Campo del importe en las condiciones de pago | maxAmountRequired |
amount |
| Descripción del recurso |
resource y otros campos dentro de las condiciones de pago |
Objeto resource de nivel superior |
| Condiciones en los datos de pago |
scheme, network y otros campos de nivel superior |
Objeto accepted que contiene las condiciones seleccionadas |
| Ejemplo de paquete TypeScript | x402-express |
@x402/express |
La ubicación donde se envían las condiciones de pago en v1 está especificada en la especificación HTTP v1. La ubicación estándar en v2 es la cabecera PAYMENT-REQUIRED. Una implementación también puede devolverlas en el cuerpo, pero debe procesarlas tomando la cabecera como referencia.
La especificación HTTP v2 describe el código de estado de la siguiente manera.
El servidor indica que se requiere un pago mediante el código de estado HTTP 402 «Payment Required».
Fuente: especificación HTTP v2 de x402
Las cabeceras de pago de v2 contienen JSON codificado en Base64. Base64 no es un método de cifrado. Use HTTPS en los servicios externos.
Solicitud HTTP 402 y secuencia de pago
Esta práctica utiliza el flujo de autorización predeterminado del esquema EVM exact. exact es un esquema para pagar un importe fijo. La secuencia sigue la especificación principal de x402 v2.
- El cliente solicita la API de pago sin información de pago.
- El servidor devuelve HTTP 402 y
PAYMENT-REQUIRED. - El cliente selecciona unas condiciones permitidas de
accepts. - El SDK firma una autorización de pago que cumple las condiciones seleccionadas.
- El cliente repite la solicitud añadiendo
PAYMENT-SIGNATURE. - El servidor verifica la autorización mediante
/verifydel facilitator. - Si la verificación se supera, el servidor procesa el recurso.
- El servidor solicita la liquidación mediante
/settle. - Tras una liquidación correcta, entrega el cuerpo de pago y
PAYMENT-RESPONSE.
Esta secuencia no es fija ni común a todos los métodos de pago. v2 también define flujos con distintos momentos de liquidación. El siguiente código solo permite el flujo predeterminado authorization.
Funciones del servidor de recursos y del facilitator
El servidor de recursos determina el precio y las condiciones de acceso al contenido. El facilitator se encarga de verificar y liquidar los pagos. Esta división de funciones se basa en la documentación oficial del facilitator.
| Componente | Función | Estado que no debe considerarse un éxito |
|---|---|---|
| Cliente | Seleccionar las condiciones y firmar la autorización de pago | Solo se ha generado la firma |
| Servidor de recursos | Declarar el precio y controlar la respuesta de pago | El cliente afirma que el pago se ha completado |
Facilitator /verify
|
Comprobar la validez de la firma y de las condiciones de pago | Solo se ha recibido isValid: true
|
Facilitator /settle
|
En esta práctica, ejecutar el pago en la cadena y devolver el resultado | Se ha enviado, pero no se ha confirmado el resultado |
/verify es una comprobación que no modifica el estado de la cadena. Por tanto, superar la verificación no significa que se hayan recibido los fondos. El saldo o el estado de la autorización pueden cambiar incluso después de la verificación.
Bloquee el cuerpo de pago si falla la verificación o la liquidación. Bloquear cuando no se ha podido confirmar el éxito se denomina fail-closed. Este comportamiento también puede comprobarse en la implementación oficial de Express.
Comparación entre la red principal y la red de prueba de Base
En la primera ejecución, use solo Base Sepolia. Circle especifica que el USDC de la red de prueba no tiene valor financiero. Las direcciones se basan en la lista de contratos de USDC de Circle.
| Aspecto | Red principal de Base | Red de prueba Base Sepolia |
|---|---|---|
| Uso | Pagos con activos reales | Pruebas de implementación y gestión de fallos |
| Chain ID | 8453 |
84532 |
| Red x402 v2 | eip155:8453 |
eip155:84532 |
| Contrato de USDC | 0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913 |
0x036CbD53842c5426634e7929541eC2318f3dCF7e |
| RPC público | https://mainnet.base.org |
https://sepolia.base.org |
| Valor financiero del token | Activo con valor financiero real | Sin valor financiero |
Consulte el Chain ID y el RPC en la documentación de la red Base. Aunque la dirección de la cartera sea la misma, los saldos son independientes si las cadenas son distintas. No registre un pago correcto en la red de prueba como una venta real.
Puede solicitar USDC de prueba en Circle Testnet Faucet. Seleccione Base Sepolia como red. En la dirección de recepción, introduzca la dirección de la cartera de prueba que usará para pagar.
Implementación de una API de pago con Node.js
Conecte paymentMiddleware antes de la ruta de pago. El siguiente ejemplo exige 0.001 USDC por llamada. El importe corresponde al precio de ejemplo de la guía oficial para vendedores. (Valor comprobado: 0.001 USDC por llamada · Fuente: docs.x402.org · Comprobado el 2026-10-28)
Archivo del servidor
Guarde el siguiente código como server.ts. El servidor solo acepta solicitudes en la interfaz local. La dirección receptora se lee de la variable de entorno PAY_TO.
import express from "express";
import { getAddress, zeroAddress } from "viem";
import { paymentMiddleware } from "@x402/express";
import { HTTPFacilitatorClient, x402ResourceServer } from "@x402/core/server";
import { ExactEvmScheme } from "@x402/evm/exact/server";
const payTo = getAddress(process.env.PAY_TO ?? "");
if (payTo === zeroAddress) throw new Error("Invalid payTo");
const network = "eip155:84532";
const resourceServer = new x402ResourceServer(
new HTTPFacilitatorClient({ url: "https://x402.org/facilitator" }),
).register(network, new ExactEvmScheme());
const app = express();
app.use((_req, res, next) => {
res.setHeader("Cache-Control", "private, no-store");
next();
});
app.use(paymentMiddleware({
"GET /paid-data": {
accepts: [{ scheme: "exact", price: "$0.001", network, payTo }],
description: "Sample paid JSON",
mimeType: "application/json",
},
}, resourceServer));
app.get("/paid-data", (_req, res) => {
res.json({ content: "Paid sample content" });
});
app.listen(4021, "127.0.0.1");
https://x402.org/facilitator es la dirección de prueba de la guía oficial. En este ejemplo se utiliza para la liquidación en Base Sepolia. Para elegir un facilitator de producción, consulte el procedimiento para la red principal de la guía para vendedores.
Ejemplo de cálculo del precio
El precio del ejemplo equivale a 1000 unidades mínimas de USDC. USDC tiene 6 decimales. La conversión de precios del SDK se basa en la implementación del servidor EVM.
0.001 USDC × 10^6 = 1000 최소 단위
| Valor que debe comprobarse | Valor esperado en este ejemplo |
|---|---|
price en la configuración del servidor |
"$0.001" |
amount en las condiciones de pago del 402 |
"1000" |
asset en las condiciones de pago |
Contrato de USDC de Base Sepolia |
payTo en las condiciones de pago |
Dirección receptora configurada |
network en las condiciones de pago |
eip155:84532 |
price es un valor de configuración del SDK. En las condiciones de pago reales de v2 se envía amount. Compare los importes enteros como cadenas de texto o como bigint.
Ejecución del servidor y comprobación del 402
Ejecute el servidor en el primer terminal Bash. El valor que debe introducir es la dirección pública receptora, no una clave privada. Mantenga este terminal abierto durante la ejecución.
read -r -p '수취 지갑 주소: ' PAY_TO
export PAY_TO
npx tsx server.ts
Envíe una solicitud sin pago desde un segundo terminal. El siguiente comando no firma ningún pago. Muestra el estado HTTP y las condiciones de pago decodificadas.
node --input-type=module <<'JS'
const response = await fetch("http://127.0.0.1:4021/paid-data");
const header = response.headers.get("PAYMENT-REQUIRED");
console.log(response.status);
console.log(header && JSON.parse(
Buffer.from(header, "base64").toString("utf8")
));
JS
La respuesta normal a una solicitud sin pago es HTTP 402. Compare las condiciones mostradas con la tabla anterior. Si el contenido de pago se devuelve directamente, corrija primero la configuración de protección de la ruta.
Selección de condiciones de pago e implementación del cliente
Restrinja el cliente para que solo firme las condiciones permitidas. Este ejemplo solo permite el precio fijo de USDC en Base Sepolia. El filtro de opciones de pago utiliza registerPolicy de la implementación oficial de x402Client.
- Guarde el siguiente código como
client.ts. - Guarde también
check-transfer.ts, que aparece en la siguiente sección. - Una vez preparados ambos archivos, continúe con el procedimiento de ejecución.
import { writeFile } from "node:fs/promises";
import { getAddress, zeroAddress, type Hex, type Hash } from "viem";
import { privateKeyToAccount } from "viem/accounts";
import { x402Client, wrapFetchWithPayment } from "@x402/fetch";
import { decodePaymentResponseHeader } from "@x402/core/http";
import { ExactEvmScheme } from "@x402/evm/exact/client";
import { checkTransfer } from "./check-transfer.js";
const key = process.env.EVM_PRIVATE_KEY ?? "";
if (!/^0x[0-9a-fA-F]{64}$/.test(key)) throw new Error("Invalid test key");
const signer = privateKeyToAccount(key as Hex);
const payTo = getAddress(process.env.PAY_TO ?? "");
if (payTo === zeroAddress) throw new Error("Invalid payTo");
const network = "eip155:84532";
const token = "0x036CbD53842c5426634e7929541eC2318f3dCF7e";
const client = new x402Client().register(network, new ExactEvmScheme(signer));
client.registerPolicy((version, options) => version === 2
? options.filter(r =>
r.scheme === "exact" && r.network === network &&
r.asset.toLowerCase() === token.toLowerCase() &&
r.payTo.toLowerCase() === payTo.toLowerCase() && r.amount === "1000" &&
(!r.extra?.assetTransferMethod || r.extra.assetTransferMethod === "eip3009") &&
(!r.extra?.paymentFlow || r.extra.paymentFlow === "authorization"))
: []);
const paidFetch = wrapFetchWithPayment(fetch, client);
const response = await paidFetch("http://127.0.0.1:4021/paid-data", {
redirect: "error",
});
const raw = response.headers.get("PAYMENT-RESPONSE");
if (!raw) throw new Error(`No settlement receipt: HTTP ${response.status}`);
const settlement = decodePaymentResponseHeader(raw);
await writeFile("settlement.json", JSON.stringify(settlement, null, 2));
if (!response.ok || !settlement.success || settlement.network !== network) {
throw new Error("Payment unresolved; inspect settlement.json before retrying");
}
const evidence = await checkTransfer(
network, settlement.transaction as Hash, signer.address, payTo, 1000n,
);
await writeFile("transfer.json", JSON.stringify(evidence, null, 2));
console.log(await response.text());
wrapFetchWithPayment se encarga de procesar el 402 y de repetir la solicitud con la firma. Su uso sigue el ejemplo oficial de fetch. Si no hay condiciones de pago permitidas, se detiene la creación del pago.
Este cliente también puede usarse en agentes de IA. Sin embargo, un límite de precio por llamada no es un límite de gasto acumulado. Gestione por separado el presupuesto para las llamadas repetidas del agente.
Verificación del evento Transfer de USDC
Compruebe los registros de transferencia de USDC mediante el hash de la transacción del resultado de liquidación. El estado correcto de la transacción, por sí solo, no confirma el destinatario. Los campos de Transfer se basan en el estándar ERC-20.
La verificación requiere los siguientes elementos.
| Elemento de verificación | Valor con el que se compara |
|---|---|
| Chain ID del RPC | Cadena permitida por el servidor |
status del recibo de la transacción |
Estado correcto |
| Dirección que emitió el evento | Contrato oficial de USDC de esa cadena |
Transfer.from |
Pagador confirmado |
Transfer.to |
Dirección receptora definida por el servidor |
Transfer.value |
Importe exigido por el servidor en unidades mínimas |
Guarde el siguiente código como check-transfer.ts. La consulta utiliza getTransactionReceipt de viem. La interpretación de los eventos se basa en parseEventLogs.
import {
createPublicClient, http, getAddress, parseEventLogs,
erc20Abi, type Address, type Hash,
} from "viem";
import { base, baseSepolia } from "viem/chains";
const configs = {
"eip155:84532": {
chain: baseSepolia,
rpc: "https://sepolia.base.org",
token: "0x036CbD53842c5426634e7929541eC2318f3dCF7e",
},
"eip155:8453": {
chain: base,
rpc: "https://mainnet.base.org",
token: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
},
} as const;
export async function checkTransfer(
network: keyof typeof configs, hash: Hash,
payer: Address, payTo: Address, amount: bigint,
) {
const cfg = configs[network];
const rpc = createPublicClient({ chain: cfg.chain, transport: http(cfg.rpc) });
if (await rpc.getChainId() !== cfg.chain.id) throw new Error("Wrong chain");
const receipt = await rpc.getTransactionReceipt({ hash });
if (receipt.status !== "success") throw new Error("Transaction failed");
const logs = parseEventLogs({
abi: erc20Abi,
eventName: "Transfer",
logs: receipt.logs.filter(
log => getAddress(log.address) === getAddress(cfg.token),
),
strict: true,
});
const transfer = logs.find(log =>
getAddress(log.args.from) === getAddress(payer) &&
getAddress(log.args.to) === getAddress(payTo) &&
log.args.value === amount,
);
if (!transfer) throw new Error("Matching USDC Transfer not found");
return {
network, transaction: hash, logIndex: transfer.logIndex,
blockHash: receipt.blockHash, blockNumber: receipt.blockNumber.toString(),
};
}
Esta función confirma que hubo una transferencia de USDC en esa transacción. Debe comprobarse por separado si corresponde a un pedido concreto de la API. En un servidor de producción, use las condiciones guardadas del pedido como valores de comparación.
No confíe en el archivo transfer.json enviado por el cliente como prueba para conceder acceso. El servidor de este ejemplo utiliza los resultados de verificación y liquidación del facilitator. Si quiere usar una consulta independiente como condición para conceder acceso, debe ejecutarla en el servidor.
Un fallo en la consulta del recibo no significa necesariamente que el pago haya fallado. Si se trata de un error del RPC, vuelva a consultar el hash de transacción guardado. Defina en la política operativa el número de confirmaciones adicionales y la respuesta a las reorganizaciones de la cadena.
Ejecución del pago de prueba y comprobación de resultados
Después de guardar todos los archivos, ejecute el ejemplo con la cartera de prueba. La comprobación de tipos no firma ni transfiere fondos. Los siguientes comandos utilizan las herramientas de TypeScript instaladas antes.
- Compruebe los tipos con el siguiente comando.
- Introduzca en el segundo terminal la misma dirección receptora que usa el servidor.
- Introduzca la clave privada de la cartera de pago de prueba sin que se muestre en pantalla.
- Ejecute el cliente una vez.
- Compruebe el resultado de liquidación y los registros de transferencia guardados.
npx tsc --noEmit --strict --skipLibCheck --target ES2022 --module NodeNext --moduleResolution NodeNext server.ts client.ts check-transfer.ts
read -r -p '같은 수취 지갑 주소: ' PAY_TO
read -r -s -p '테스트 결제 지갑 개인키: ' EVM_PRIVATE_KEY
export PAY_TO EVM_PRIVATE_KEY
npx tsx client.ts
unset EVM_PRIVATE_KEY
| Resultado | Significado | Qué comprobar |
|---|---|---|
settlement.json |
Resultado de liquidación devuelto por el servidor |
success, network, transaction
|
transfer.json |
Registro de transferencia encontrado en la consulta RPC | Cadena, hash de transacción, posición del registro e información del bloque |
| Cuerpo de pago en la consola | Datos mostrados tras la verificación de este cliente | Comprobar que sea el contenido solicitado |
Una nueva ejecución del cliente puede generar un nuevo pago. Este ejemplo mínimo no incluye un almacenamiento para evitar duplicados por pedido. Añada la función de reintento solo después de cumplir las condiciones de la siguiente sección.
Tratamiento según las condiciones de fallo de verificación
En las pruebas de fallo, compruebe que no se exponga el cuerpo de pago. Si solo comprueba el estado HTTP, puede pasar por alto un fallo de bloqueo. Consulte el middleware oficial de Express como referencia del comportamiento esperado.
| Condición de prueba | Tratamiento esperado | Comprobación adicional |
|---|---|---|
| Sin cabecera de pago | Devolver 402 y las condiciones de pago | Sin cuerpo de pago |
| Se propone otro token o destinatario | Rechazar mediante la política del cliente | No generar una firma |
| Firma incorrecta | Bloquear por fallo de verificación | No ejecutar el manejador de pago |
| Saldo insuficiente | Bloquear por fallo de verificación o liquidación | No registrar la liquidación como correcta |
| Resultado de liquidación fallido | Bloquear la respuesta de pago | No enviar ni siquiera el cuerpo ya preparado |
| Retraso en la respuesta del facilitator | Mantener pendiente al no haberse confirmado el éxito | Prohibir la generación automática de una nueva autorización |
| Error al consultar el recibo por RPC | Conservar el hash de transacción y volver a consultar | No dar por hecho que el pago ha fallado |
En el flujo de autorización predeterminado, el manejador se ejecuta antes de la liquidación. Un fallo de liquidación no revierte las operaciones externas. Empiece por consultas sin efectos secundarios, como en este ejemplo.
El envío de correos electrónicos o la creación de pedidos externos requieren un diseño aparte. Registre conjuntamente el estado del pago y el de la operación. Defina qué se volverá a ejecutar en caso de fallo para reducir las operaciones duplicadas.
Pérdida de respuesta tras la liquidación y recuperación mediante reenvío
Guarde como estados separados la finalización del pago y la entrega del contenido. El pago puede haberse completado y, aun así, perderse la conexión de respuesta. El tratamiento de estas situaciones se basa en la documentación de la extensión Payment-Identifier.
La propiedad que evita procesar una operación por duplicado aunque se solicite de nuevo se denomina idempotencia. payment-identifier proporciona un identificador de pago para este fin. Añadir el identificador no basta para que esta función quede implementada automáticamente.
Comparación entre pagos duplicados y reenvíos
Debe distinguirse entre impedir la reutilización de una misma firma y evitar pedidos duplicados. EIP-3009 impide reutilizar el nonce de una autorización ya utilizada. Este comportamiento está definido en la especificación ERC-3009.
| Situación | Desde la perspectiva de la autorización en la cadena | Desde la perspectiva de la operación de la API |
|---|---|---|
| Volver a liquidar la misma autorización | Sujeta a la comprobación de nonce ya utilizado | Es necesario consultar el resultado existente |
| Crear una nueva autorización para el mismo pedido | Puede tratarse como una autorización independiente | Es necesario evitar pagos duplicados |
| Pérdida de respuesta tras una liquidación correcta | El movimiento de activos puede haberse completado | Es necesario volver a entregar el contenido |
| Tiempo de espera agotado tras solicitar la liquidación | El resultado aún es incierto | Es necesario mantener el estado pendiente y comprobar la liquidación |
El siguiente procedimiento es una propuesta de diseño para conectar la extensión oficial con el almacenamiento de producción. No está incluido en el código mínimo anterior. Para aplicarlo en producción, añada almacenamiento persistente y control de solicitudes simultáneas.
- Declare en el servidor la compatibilidad con la extensión
payment-identifier. - Conserve en el cliente el identificador de la solicitud lógica.
- Vincule en el servidor el identificador con el pagador y el contenido de la solicitud.
- Registre de forma atómica el estado de procesamiento para impedir ejecuciones simultáneas.
- Cuando la liquidación se complete correctamente, guarde las pruebas de la transacción y el resultado de la respuesta.
- Si los permisos y el contenido de la nueva solicitud coinciden, devuelva el resultado guardado.
- Si el resultado de liquidación es incierto, compruebe primero la autorización existente.
Un identificador de pago no es una contraseña ni un token de acceso. No devuelva contenido de pago almacenado en caché a una solicitud solo porque conozca el identificador. Compruebe también si se está reutilizando para otro usuario o con otro cuerpo de solicitud.
Guarde juntos la cadena, el hash de transacción y la posición del registro en los registros de producción. Vincule estos datos al pedido para impedir su reutilización en otros pedidos. La coincidencia de Transfer por sí sola no demuestra a qué pedido corresponde.
Errores frecuentes en la implementación de pagos
Confundir los campos de versión y las señales de éxito puede dar lugar a una evaluación incorrecta del pago. Use la siguiente tabla en la revisión del despliegue. Las diferencias entre versiones se basan en la guía de migración de x402.
| Error frecuente | Criterio correcto |
|---|---|
Interpretar extra.version: "2" como la versión de x402 |
Comprobar la versión del protocolo mediante x402Version
|
Usar maxAmountRequired en v2 |
Usar amount para el importe de las condiciones de pago |
Crear por cuenta propia la cabecera X-PAYMENT-REQUIRED
|
Usar el cuerpo en v1 y PAYMENT-REQUIRED en v2 |
Tratar isValid: true como confirmación de recepción de fondos |
Comprobar por separado el resultado de /settle
|
Tratar el campo to de nivel superior de la transacción como el destinatario de USDC |
Comprobar Transfer.to de USDC |
| Suponer que el firmante y el remitente de la transacción son el mismo | Comparar el pagador de la autorización con Transfer.from
|
| Sumar los importes recibidos en la red de prueba a las ventas | Separar los libros de la red principal y de la red de prueba |
| Crear un nuevo pago cada vez que se agota el tiempo de espera | Recuperar primero el pedido existente y el estado de su autorización |
| Equiparar la versión del paquete SDK con la del protocolo | Gestionar por separado la versión del paquete y x402Version
|
La información de dominio de la firma de USDC también contiene una cadena de versión. Ese valor tiene una finalidad distinta de la versión del protocolo x402. Consulte la estructura del dominio de firma en la especificación ERC-3009.
Revisión de seguridad y alcance de la confianza en servicios externos
Controle desde el servidor la decisión de considerar un pago correcto. La respuesta del facilitator externo también es un elemento en el que se confía de forma explícita. La arquitectura que permite operarlo por cuenta propia se explica en la documentación del facilitator.
- No dé acceso al contenido basándose en un mensaje de éxito del cliente.
- Compare la cadena, el token, el importe y el destinatario declarados por el servidor.
- No registre claves privadas ni frases semilla.
- Excluya también las firmas completas de autorización de los registros de acceso habituales.
- Limite el tamaño de las cabeceras de pago y el tiempo de procesamiento de las solicitudes.
- Compruebe que las respuestas de pago no queden en cachés compartidas.
- Separe las ubicaciones de almacenamiento de las claves de prueba y de producción.
- No cree una ruta alternativa sin pago cuando falle el facilitator.
- Pruebe de forma efectiva la caducidad de las autorizaciones y las solicitudes duplicadas.
Las dependencias fijadas para esta práctica aún presentan advertencias de seguridad. npm audit informó de un aviso relacionado con zod. Consulte los detalles en el aviso de seguridad de GitHub.
npm audit
Antes de desplegar en producción, compruebe la compatibilidad del SDK con la versión corregida. Forzar un cambio de versión principal puede alterar el comportamiento. No use esta práctica como una configuración de despliegue cuya seguridad ya haya sido validada.
Comparación entre un servidor propio y Cloudflare Gateway
Al usar Cloudflare Gateway, cambia el método de verificación del servidor de origen. La documentación del 30 de septiembre de 2026 especifica el uso de x402 v2. La siguiente comparación se basa en la documentación de x402 de Cloudflare.
| Aspecto | Método con Express de este artículo | Cloudflare Monetization Gateway |
|---|---|---|
| Procesamiento del pago del cliente | Middleware de Express | Gateway |
| Punto de verificación del servidor de origen | Integración con el facilitator elegido | Verificación del JWT PAYMENT-CONTEXT
|
| Entrega del resultado de liquidación |
PAYMENT-RESPONSE del middleware |
Gateway genera el recibo de liquidación |
| Comprobaciones adicionales | Cadenas admitidas y autenticación del facilitator | Verificación de la firma JWT y protección del acceso al origen |
PAYMENT-CONTEXT es una cabecera entre Gateway y el servidor de origen. No es la cabecera de firma de un cliente x402 convencional. Para la verificación en el origen, siga la documentación Payment validation de Cloudflare.
Aunque se use Gateway, no basta con decodificar el JWT. Verifique la firma con la clave indicada en la documentación. Si falta la cabecera o falla la verificación, bloquee el contenido de pago.
Distinción entre uso real y registros de liquidación
El número de transferencias en la cadena, por sí solo, no demuestra el consumo de contenido. Calcule las métricas operativas vinculando la liquidación con la entrega de la respuesta. Esta es una propuesta de diseño basada en el flujo de pago y el comportamiento de los reenvíos.
| Registro | Pregunta que permite responder | Registro adicional necesario |
|---|---|---|
| Respuesta 402 | Cuántas veces se han solicitado las condiciones de pago | Si el pago se ha producido realmente |
| Verificación correcta | Si la autorización era válida | Resultado de liquidación |
| Transferencia de USDC | Si se han movido los activos | Pedido al que corresponde |
| Liquidación completada por pedido | Si se ha pagado la solicitud de pago | Estado de entrega de la respuesta |
| Registro de reentrega | Si se ha recuperado una solicitud ya pagada | Identificador que permita distinguirla de un pago nuevo |
Distinga las solicitudes de prueba al calcular el uso real. Marque también por separado los reintentos de un mismo pedido. No presente el volumen de transacciones en sí como prueba de demanda de la API ni como garantía de ingresos.
Procedimiento de transición a la red principal de Base
Considere el paso a la red principal después de comprobar los casos correctos y de fallo en la red de prueba. Cambiar solo la cadena de texto de la red no completa la transición. El procedimiento de referencia sigue la guía oficial para vendedores.
- Compruebe que el facilitator elegido admita la red principal de Base.
- Compruebe en
/supportedla compatibilidad con v2,exactyeip155:8453. - Configure la autenticación y las condiciones de uso exigidas por el proveedor.
- Cambie la red tanto en el servidor como en el cliente.
- Cambie la dirección permitida de USDC del cliente por la dirección de la red principal.
- Vuelva a contrastar el importe de la respuesta 402 y la dirección receptora real.
- Integre el almacenamiento para solicitudes duplicadas y el procedimiento de recuperación ante fallos.
- Complete la revisión de seguridad de las dependencias de producción.
- Compruebe la transferencia real y la entrega del contenido con el importe pequeño configurado.
La compatibilidad con varias cadenas no significa que se admitan todas las combinaciones. Compruebe conjuntamente el alcance de la compatibilidad del SDK y del facilitator. La referencia para esta comprobación es la documentación sobre compatibilidad con redes y tokens.
FAQ
¿En qué se diferencia x402 de la confirmación de un depósito normal de USDC?
Durante la solicitud HTTP se comunican las condiciones de pago y se repite la solicitud con una autorización de pago firmada. A diferencia del método que coteja después los registros de depósitos, vincula el proceso de pago con la solicitud de un recurso de pago.
¿Cuáles son las cabeceras de pago de x402 v2?
Las condiciones de pago se transmiten mediante PAYMENT-REQUIRED y la carga útil de pago mediante PAYMENT-SIGNATURE. El resultado de la liquidación se transmite mediante PAYMENT-RESPONSE.
¿Existe la cabecera X-PAYMENT-REQUIRED en v1?
La especificación oficial HTTP v1 incluye las condiciones iniciales de pago en el cuerpo de la respuesta JSON. Para la carga útil de pago y el resultado de la liquidación se usan X-PAYMENT y X-PAYMENT-RESPONSE, respectivamente.
¿El éxito de /verify significa que el pago se ha completado?
El éxito de /verify significa que la autorización de pago es válida. En esta práctica, debes comprobar por separado que el resultado de /settle sea satisfactorio.
¿Se pueden considerar los USDC de prueba de Base Sepolia como ingresos reales?
Circle indica expresamente que los USDC de la red de pruebas no tienen valor financiero. Registra las liquidaciones de la red de pruebas por separado de las ventas reales.
¿Hay que introducir una clave privada en el servidor receptor?
En el servidor receptor de este ejemplo solo se configura la dirección pública de recepción. La clave privada usada para la autorización de pago se lee en el cliente de pago.
¿Cuál es el valor de amount para 0.001 USDC?
Al aplicar los 6 decimales de USDC, el valor en la unidad mínima es 1000. En las condiciones de pago de v2 se usa la cadena "1000".
¿Un recibo de transacción satisfactorio confirma también la recepción de USDC?
El estado satisfactorio de la transacción no basta. Coteja el pagador, el destinatario y el importe en el evento Transfer del contrato oficial de USDC.
¿Es seguro reenviar la misma solicitud de pago?
La prevención de la reutilización del nonce de una misma autorización y la prevención de pedidos duplicados son cuestiones distintas. Antes de reintentar, comprueba el estado del pago existente e implementa un mecanismo de idempotencia por pedido.
¿Si no hay PAYMENT-RESPONSE, basta con volver a pagar?
Si se pierde la respuesta o se agota el tiempo de espera, el resultado de la liquidación puede ser incierto. No empieces creando una nueva autorización; comprueba el estado de liquidación de la solicitud existente.
¿Con x402 hay que usar únicamente el facilitador de una empresa específica?
La arquitectura oficial permite tanto usar un facilitador externo como operar uno propio. Comprueba que la implementación elegida admita la versión del protocolo, el método de pago y la cadena que necesitas.
¿También se limita automáticamente el gasto de los agentes de IA?
Este ejemplo solo limita las condiciones de pago de cada solicitud. Gestiona el gasto acumulado por las llamadas repetidas con una política de presupuesto independiente.
¿PAYMENT-CONTEXT de Cloudflare es una cabecera estándar de firma de pago?
PAYMENT-CONTEXT es un JWT que Gateway envía al servidor de origen. Su finalidad es distinta de la de PAYMENT-SIGNATURE del cliente.
¿Se puede desplegar el ejemplo directamente en la red principal?
Este código es una configuración mínima para pruebas. Antes de desplegarlo en producción, compruebe las advertencias de seguridad de las dependencias, la gestión de solicitudes duplicadas, la autenticación del facilitador y la liquidación real.
Sources
- Especificación del protocolo x402 v2
- Transporte HTTP de x402 v1
- Transporte HTTP de x402 v2
- Guía de migración de x402: de V1 a V2
- Funciones y responsabilidades del facilitador de x402
- Guía de inicio rápido de x402 para vendedores
- Guía de inicio rápido de x402 para compradores
- Ejemplo del cliente fetch oficial de x402 en TypeScript
- Implementación del middleware de Express para x402
- Selección de condiciones de pago e implementación de políticas en x402Client
- Implementación de la conversión de precios en el servidor de ExactEvmScheme de x402
- Dirección del contrato de USDC de Circle
- Información sobre la red principal de Base y la red Base Sepolia
- Circle Testnet Faucet
- viem getTransactionReceipt
- viem parseEventLogs
- Estándar de tokens ERC-20
- ERC-3009 Transferencia con autorización
- Extensión de idempotencia Payment-Identifier de x402
- Protocolo x402 de Cloudflare Monetization Gateway
- Validación de pagos de Cloudflare Monetization Gateway
- Redes y tokens compatibles con x402
- Aviso de seguridad de GitHub: agotamiento de memoria por la validación de colecciones de gran tamaño en Zod
Images

