{"content_id":"gyaevhk2bq","slug":"x402-payments-2026-v2-base-usdc-settlement-guide","locale":"es","schema_type":"HowTo","category":"tutorial","category_name":"Tutorial","title":"Pagos x402 2026 v2: implementar y verificar la liquidación","summary":"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.","sponsorship_disclosure":null,"affiliate_disclosure":null,"commerce_disclosure":null,"author":{"name":"Equipo editorial de Injoys","url":"https://injoys.com/ko/about"},"key_points":["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."],"content_markdown":"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.\n\nLa información sobre importes y cadenas se basa en la documentación oficial de x402, Base y Circle enlazada como fuente.\n\n## Preparación e instalación para la práctica\n\nPrepare 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](https://docs.x402.org/getting-started/quickstart-for-sellers).\n\n1. Prepare una dirección de cartera EVM para recibir los pagos.\n2. Prepare otra cartera de prueba para hacer los pagos.\n3. Consiga USDC de prueba de Base Sepolia para la cartera de pago.\n4. Cree el proyecto de práctica con los siguientes comandos.\n5. Guarde los archivos TypeScript que aparecen más adelante en la misma carpeta.\n\n```bash\nmkdir x402-demo\ncd x402-demo\nnpm init -y\nnpm pkg set type=module\nnpm install --save-exact express@5.3.0 viem@2.57.12 @x402/core@2.28.0 @x402/express@2.28.0 @x402/evm@2.28.0 @x402/fetch@2.28.0\nnpm install --save-dev --save-exact typescript tsx @types/node @types/express\n```\n\nEl 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](https://docs.x402.org/getting-started/quickstart-for-buyers).\n\nLa 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.\n\n## Comparación entre x402 v1 y v2\n\nAl 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](https://docs.x402.org/guides/migration-v1-to-v2).\n\n| Aspecto | v1 | v2 |\n|---|---|---|\n| Versión del protocolo | `x402Version: 1` | `x402Version: 2` |\n| Condiciones de pago iniciales | Cuerpo JSON de la respuesta 402 | Cabecera de respuesta `PAYMENT-REQUIRED` |\n| Datos de pago firmados | Cabecera de solicitud `X-PAYMENT` | Cabecera de solicitud `PAYMENT-SIGNATURE` |\n| Resultado de la liquidación | Cabecera de respuesta `X-PAYMENT-RESPONSE` | Cabecera de respuesta `PAYMENT-RESPONSE` |\n| Identificador de la red principal de Base | `base` | `eip155:8453` |\n| Identificador de Base Sepolia | `base-sepolia` | `eip155:84532` |\n| Campo del importe en las condiciones de pago | `maxAmountRequired` | `amount` |\n| Descripción del recurso | `resource` y otros campos dentro de las condiciones de pago | Objeto `resource` de nivel superior |\n| Condiciones en los datos de pago | `scheme`, `network` y otros campos de nivel superior | Objeto `accepted` que contiene las condiciones seleccionadas |\n| Ejemplo de paquete TypeScript | `x402-express` | `@x402/express` |\n\nLa ubicación donde se envían las condiciones de pago en v1 está especificada en la [especificación HTTP v1](https://github.com/x402-foundation/x402/blob/main/specs/transports-v1/http.md). 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.\n\nLa [especificación HTTP v2](https://github.com/x402-foundation/x402/blob/main/specs/transports-v2/http.md) describe el código de estado de la siguiente manera.\n\n\u003e El servidor indica que se requiere un pago mediante el código de estado HTTP 402 «Payment Required».\n\u003e\n\u003e Fuente: especificación HTTP v2 de x402\n\nLas cabeceras de pago de v2 contienen JSON codificado en Base64. Base64 no es un método de cifrado. Use HTTPS en los servicios externos.\n\n## Solicitud HTTP 402 y secuencia de pago\n\nEsta 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](https://github.com/x402-foundation/x402/blob/main/specs/x402-specification-v2.md).\n\n1. El cliente solicita la API de pago sin información de pago.\n2. El servidor devuelve HTTP 402 y `PAYMENT-REQUIRED`.\n3. El cliente selecciona unas condiciones permitidas de `accepts`.\n4. El SDK firma una autorización de pago que cumple las condiciones seleccionadas.\n5. El cliente repite la solicitud añadiendo `PAYMENT-SIGNATURE`.\n6. El servidor verifica la autorización mediante `/verify` del facilitator.\n7. Si la verificación se supera, el servidor procesa el recurso.\n8. El servidor solicita la liquidación mediante `/settle`.\n9. Tras una liquidación correcta, entrega el cuerpo de pago y `PAYMENT-RESPONSE`.\n\nEsta 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`.\n\n### Funciones del servidor de recursos y del facilitator\n\nEl 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](https://github.com/x402-foundation/x402/blob/main/docs/core-concepts/facilitator.md).\n\n| Componente | Función | Estado que no debe considerarse un éxito |\n|---|---|---|\n| Cliente | Seleccionar las condiciones y firmar la autorización de pago | Solo se ha generado la firma |\n| Servidor de recursos | Declarar el precio y controlar la respuesta de pago | El cliente afirma que el pago se ha completado |\n| Facilitator `/verify` | Comprobar la validez de la firma y de las condiciones de pago | Solo se ha recibido `isValid: true` |\n| 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 |\n\n`/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.\n\nBloquee 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](https://github.com/x402-foundation/x402/blob/main/typescript/packages/http/express/src/index.ts).\n\n## Comparación entre la red principal y la red de prueba de Base\n\nEn 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](https://developers.circle.com/stablecoins/usdc-contract-addresses).\n\n| Aspecto | Red principal de Base | Red de prueba Base Sepolia |\n|---|---|---|\n| Uso | Pagos con activos reales | Pruebas de implementación y gestión de fallos |\n| Chain ID | `8453` | `84532` |\n| Red x402 v2 | `eip155:8453` | `eip155:84532` |\n| Contrato de USDC | `0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913` | `0x036CbD53842c5426634e7929541eC2318f3dCF7e` |\n| RPC público | `https://mainnet.base.org` | `https://sepolia.base.org` |\n| Valor financiero del token | Activo con valor financiero real | Sin valor financiero |\n\nConsulte el Chain ID y el RPC en la [documentación de la red Base](https://docs.base.org/get-started/connect-to-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.\n\nPuede solicitar USDC de prueba en [Circle Testnet Faucet](https://faucet.circle.com/). 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.\n\n## Implementación de una API de pago con Node.js\n\nConecte `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)\n\n### Archivo del servidor\n\nGuarde 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`.\n\n```typescript\nimport express from \"express\";\nimport { getAddress, zeroAddress } from \"viem\";\nimport { paymentMiddleware } from \"@x402/express\";\nimport { HTTPFacilitatorClient, x402ResourceServer } from \"@x402/core/server\";\nimport { ExactEvmScheme } from \"@x402/evm/exact/server\";\n\nconst payTo = getAddress(process.env.PAY_TO ?? \"\");\nif (payTo === zeroAddress) throw new Error(\"Invalid payTo\");\nconst network = \"eip155:84532\";\nconst resourceServer = new x402ResourceServer(\n  new HTTPFacilitatorClient({ url: \"https://x402.org/facilitator\" }),\n).register(network, new ExactEvmScheme());\n\nconst app = express();\napp.use((_req, res, next) =\u003e {\n  res.setHeader(\"Cache-Control\", \"private, no-store\");\n  next();\n});\napp.use(paymentMiddleware({\n  \"GET /paid-data\": {\n    accepts: [{ scheme: \"exact\", price: \"$0.001\", network, payTo }],\n    description: \"Sample paid JSON\",\n    mimeType: \"application/json\",\n  },\n}, resourceServer));\napp.get(\"/paid-data\", (_req, res) =\u003e {\n  res.json({ content: \"Paid sample content\" });\n});\napp.listen(4021, \"127.0.0.1\");\n```\n\n`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](https://docs.x402.org/getting-started/quickstart-for-sellers#running-on-mainnet).\n\n### Ejemplo de cálculo del precio\n\nEl 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](https://github.com/x402-foundation/x402/blob/main/typescript/packages/mechanisms/evm/src/exact/server/scheme.ts).\n\n```text\n0.001 USDC × 10^6 = 1000 최소 단위\n```\n\n| Valor que debe comprobarse | Valor esperado en este ejemplo |\n|---|---|\n| `price` en la configuración del servidor | `\"$0.001\"` |\n| `amount` en las condiciones de pago del 402 | `\"1000\"` |\n| `asset` en las condiciones de pago | Contrato de USDC de Base Sepolia |\n| `payTo` en las condiciones de pago | Dirección receptora configurada |\n| `network` en las condiciones de pago | `eip155:84532` |\n\n`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`.\n\n### Ejecución del servidor y comprobación del 402\n\nEjecute 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.\n\n```bash\nread -r -p '수취 지갑 주소: ' PAY_TO\nexport PAY_TO\nnpx tsx server.ts\n```\n\nEnví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.\n\n```bash\nnode --input-type=module \u003c\u003c'JS'\nconst response = await fetch(\"http://127.0.0.1:4021/paid-data\");\nconst header = response.headers.get(\"PAYMENT-REQUIRED\");\nconsole.log(response.status);\nconsole.log(header \u0026\u0026 JSON.parse(\n  Buffer.from(header, \"base64\").toString(\"utf8\")\n));\nJS\n```\n\nLa 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.\n\n## Selección de condiciones de pago e implementación del cliente\n\nRestrinja 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](https://github.com/x402-foundation/x402/blob/main/typescript/packages/core/src/client/x402Client.ts).\n\n1. Guarde el siguiente código como `client.ts`.\n2. Guarde también `check-transfer.ts`, que aparece en la siguiente sección.\n3. Una vez preparados ambos archivos, continúe con el procedimiento de ejecución.\n\n```typescript\nimport { writeFile } from \"node:fs/promises\";\nimport { getAddress, zeroAddress, type Hex, type Hash } from \"viem\";\nimport { privateKeyToAccount } from \"viem/accounts\";\nimport { x402Client, wrapFetchWithPayment } from \"@x402/fetch\";\nimport { decodePaymentResponseHeader } from \"@x402/core/http\";\nimport { ExactEvmScheme } from \"@x402/evm/exact/client\";\nimport { checkTransfer } from \"./check-transfer.js\";\n\nconst key = process.env.EVM_PRIVATE_KEY ?? \"\";\nif (!/^0x[0-9a-fA-F]{64}$/.test(key)) throw new Error(\"Invalid test key\");\nconst signer = privateKeyToAccount(key as Hex);\nconst payTo = getAddress(process.env.PAY_TO ?? \"\");\nif (payTo === zeroAddress) throw new Error(\"Invalid payTo\");\nconst network = \"eip155:84532\";\nconst token = \"0x036CbD53842c5426634e7929541eC2318f3dCF7e\";\nconst client = new x402Client().register(network, new ExactEvmScheme(signer));\nclient.registerPolicy((version, options) =\u003e version === 2\n  ? options.filter(r =\u003e\n      r.scheme === \"exact\" \u0026\u0026 r.network === network \u0026\u0026\n      r.asset.toLowerCase() === token.toLowerCase() \u0026\u0026\n      r.payTo.toLowerCase() === payTo.toLowerCase() \u0026\u0026 r.amount === \"1000\" \u0026\u0026\n      (!r.extra?.assetTransferMethod || r.extra.assetTransferMethod === \"eip3009\") \u0026\u0026\n      (!r.extra?.paymentFlow || r.extra.paymentFlow === \"authorization\"))\n  : []);\n\nconst paidFetch = wrapFetchWithPayment(fetch, client);\nconst response = await paidFetch(\"http://127.0.0.1:4021/paid-data\", {\n  redirect: \"error\",\n});\nconst raw = response.headers.get(\"PAYMENT-RESPONSE\");\nif (!raw) throw new Error(`No settlement receipt: HTTP ${response.status}`);\nconst settlement = decodePaymentResponseHeader(raw);\nawait writeFile(\"settlement.json\", JSON.stringify(settlement, null, 2));\nif (!response.ok || !settlement.success || settlement.network !== network) {\n  throw new Error(\"Payment unresolved; inspect settlement.json before retrying\");\n}\nconst evidence = await checkTransfer(\n  network, settlement.transaction as Hash, signer.address, payTo, 1000n,\n);\nawait writeFile(\"transfer.json\", JSON.stringify(evidence, null, 2));\nconsole.log(await response.text());\n```\n\n`wrapFetchWithPayment` se encarga de procesar el 402 y de repetir la solicitud con la firma. Su uso sigue el [ejemplo oficial de fetch](https://github.com/x402-foundation/x402/tree/main/examples/typescript/clients/fetch). Si no hay condiciones de pago permitidas, se detiene la creación del pago.\n\nEste 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.\n\n## Verificación del evento Transfer de USDC\n\nCompruebe 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](https://eips.ethereum.org/EIPS/eip-20).\n\nLa verificación requiere los siguientes elementos.\n\n| Elemento de verificación | Valor con el que se compara |\n|---|---|\n| Chain ID del RPC | Cadena permitida por el servidor |\n| `status` del recibo de la transacción | Estado correcto |\n| Dirección que emitió el evento | Contrato oficial de USDC de esa cadena |\n| `Transfer.from` | Pagador confirmado |\n| `Transfer.to` | Dirección receptora definida por el servidor |\n| `Transfer.value` | Importe exigido por el servidor en unidades mínimas |\n\nGuarde el siguiente código como `check-transfer.ts`. La consulta utiliza [getTransactionReceipt](https://viem.sh/docs/actions/public/getTransactionReceipt) de viem. La interpretación de los eventos se basa en [parseEventLogs](https://viem.sh/docs/contract/parseEventLogs).\n\n```typescript\nimport {\n  createPublicClient, http, getAddress, parseEventLogs,\n  erc20Abi, type Address, type Hash,\n} from \"viem\";\nimport { base, baseSepolia } from \"viem/chains\";\n\nconst configs = {\n  \"eip155:84532\": {\n    chain: baseSepolia,\n    rpc: \"https://sepolia.base.org\",\n    token: \"0x036CbD53842c5426634e7929541eC2318f3dCF7e\",\n  },\n  \"eip155:8453\": {\n    chain: base,\n    rpc: \"https://mainnet.base.org\",\n    token: \"0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913\",\n  },\n} as const;\n\nexport async function checkTransfer(\n  network: keyof typeof configs, hash: Hash,\n  payer: Address, payTo: Address, amount: bigint,\n) {\n  const cfg = configs[network];\n  const rpc = createPublicClient({ chain: cfg.chain, transport: http(cfg.rpc) });\n  if (await rpc.getChainId() !== cfg.chain.id) throw new Error(\"Wrong chain\");\n  const receipt = await rpc.getTransactionReceipt({ hash });\n  if (receipt.status !== \"success\") throw new Error(\"Transaction failed\");\n  const logs = parseEventLogs({\n    abi: erc20Abi,\n    eventName: \"Transfer\",\n    logs: receipt.logs.filter(\n      log =\u003e getAddress(log.address) === getAddress(cfg.token),\n    ),\n    strict: true,\n  });\n  const transfer = logs.find(log =\u003e\n    getAddress(log.args.from) === getAddress(payer) \u0026\u0026\n    getAddress(log.args.to) === getAddress(payTo) \u0026\u0026\n    log.args.value === amount,\n  );\n  if (!transfer) throw new Error(\"Matching USDC Transfer not found\");\n  return {\n    network, transaction: hash, logIndex: transfer.logIndex,\n    blockHash: receipt.blockHash, blockNumber: receipt.blockNumber.toString(),\n  };\n}\n```\n\nEsta 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.\n\nNo 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.\n\nUn 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.\n\n## Ejecución del pago de prueba y comprobación de resultados\n\nDespué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.\n\n1. Compruebe los tipos con el siguiente comando.\n2. Introduzca en el segundo terminal la misma dirección receptora que usa el servidor.\n3. Introduzca la clave privada de la cartera de pago de prueba sin que se muestre en pantalla.\n4. Ejecute el cliente una vez.\n5. Compruebe el resultado de liquidación y los registros de transferencia guardados.\n\n```bash\nnpx tsc --noEmit --strict --skipLibCheck --target ES2022 --module NodeNext --moduleResolution NodeNext server.ts client.ts check-transfer.ts\nread -r -p '같은 수취 지갑 주소: ' PAY_TO\nread -r -s -p '테스트 결제 지갑 개인키: ' EVM_PRIVATE_KEY\nexport PAY_TO EVM_PRIVATE_KEY\nnpx tsx client.ts\nunset EVM_PRIVATE_KEY\n```\n\n| Resultado | Significado | Qué comprobar |\n|---|---|---|\n| `settlement.json` | Resultado de liquidación devuelto por el servidor | `success`, `network`, `transaction` |\n| `transfer.json` | Registro de transferencia encontrado en la consulta RPC | Cadena, hash de transacción, posición del registro e información del bloque |\n| Cuerpo de pago en la consola | Datos mostrados tras la verificación de este cliente | Comprobar que sea el contenido solicitado |\n\nUna 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.\n\n## Tratamiento según las condiciones de fallo de verificación\n\nEn 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](https://github.com/x402-foundation/x402/blob/main/typescript/packages/http/express/src/index.ts) como referencia del comportamiento esperado.\n\n| Condición de prueba | Tratamiento esperado | Comprobación adicional |\n|---|---|---|\n| Sin cabecera de pago | Devolver 402 y las condiciones de pago | Sin cuerpo de pago |\n| Se propone otro token o destinatario | Rechazar mediante la política del cliente | No generar una firma |\n| Firma incorrecta | Bloquear por fallo de verificación | No ejecutar el manejador de pago |\n| Saldo insuficiente | Bloquear por fallo de verificación o liquidación | No registrar la liquidación como correcta |\n| Resultado de liquidación fallido | Bloquear la respuesta de pago | No enviar ni siquiera el cuerpo ya preparado |\n| 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 |\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 |\n\nEn 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.\n\nEl 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.\n\n## Pérdida de respuesta tras la liquidación y recuperación mediante reenvío\n\nGuarde 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](https://docs.x402.org/extensions/payment-identifier).\n\nLa 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.\n\n### Comparación entre pagos duplicados y reenvíos\n\nDebe 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](https://eips.ethereum.org/EIPS/eip-3009).\n\n| Situación | Desde la perspectiva de la autorización en la cadena | Desde la perspectiva de la operación de la API |\n|---|---|---|\n| Volver a liquidar la misma autorización | Sujeta a la comprobación de nonce ya utilizado | Es necesario consultar el resultado existente |\n| Crear una nueva autorización para el mismo pedido | Puede tratarse como una autorización independiente | Es necesario evitar pagos duplicados |\n| Pérdida de respuesta tras una liquidación correcta | El movimiento de activos puede haberse completado | Es necesario volver a entregar el contenido |\n| 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 |\n\nEl 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.\n\n1. Declare en el servidor la compatibilidad con la extensión `payment-identifier`.\n2. Conserve en el cliente el identificador de la solicitud lógica.\n3. Vincule en el servidor el identificador con el pagador y el contenido de la solicitud.\n4. Registre de forma atómica el estado de procesamiento para impedir ejecuciones simultáneas.\n5. Cuando la liquidación se complete correctamente, guarde las pruebas de la transacción y el resultado de la respuesta.\n6. Si los permisos y el contenido de la nueva solicitud coinciden, devuelva el resultado guardado.\n7. Si el resultado de liquidación es incierto, compruebe primero la autorización existente.\n\nUn 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.\n\nGuarde 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.\n\n## Errores frecuentes en la implementación de pagos\n\nConfundir 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](https://docs.x402.org/guides/migration-v1-to-v2).\n\n| Error frecuente | Criterio correcto |\n|---|---|\n| Interpretar `extra.version: \"2\"` como la versión de x402 | Comprobar la versión del protocolo mediante `x402Version` |\n| Usar `maxAmountRequired` en v2 | Usar `amount` para el importe de las condiciones de pago |\n| Crear por cuenta propia la cabecera `X-PAYMENT-REQUIRED` | Usar el cuerpo en v1 y `PAYMENT-REQUIRED` en v2 |\n| Tratar `isValid: true` como confirmación de recepción de fondos | Comprobar por separado el resultado de `/settle` |\n| Tratar el campo `to` de nivel superior de la transacción como el destinatario de USDC | Comprobar `Transfer.to` de USDC |\n| Suponer que el firmante y el remitente de la transacción son el mismo | Comparar el pagador de la autorización con `Transfer.from` |\n| 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 |\n| 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 |\n| Equiparar la versión del paquete SDK con la del protocolo | Gestionar por separado la versión del paquete y `x402Version` |\n\nLa 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](https://eips.ethereum.org/EIPS/eip-3009).\n\n## Revisión de seguridad y alcance de la confianza en servicios externos\n\nControle 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](https://github.com/x402-foundation/x402/blob/main/docs/core-concepts/facilitator.md).\n\n- No dé acceso al contenido basándose en un mensaje de éxito del cliente.\n- Compare la cadena, el token, el importe y el destinatario declarados por el servidor.\n- No registre claves privadas ni frases semilla.\n- Excluya también las firmas completas de autorización de los registros de acceso habituales.\n- Limite el tamaño de las cabeceras de pago y el tiempo de procesamiento de las solicitudes.\n- Compruebe que las respuestas de pago no queden en cachés compartidas.\n- Separe las ubicaciones de almacenamiento de las claves de prueba y de producción.\n- No cree una ruta alternativa sin pago cuando falle el facilitator.\n- Pruebe de forma efectiva la caducidad de las autorizaciones y las solicitudes duplicadas.\n\nLas 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](https://github.com/advisories/GHSA-mrhx-c7xc-m3w5).\n\n```bash\nnpm audit\n```\n\nAntes 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.\n\n### Comparación entre un servidor propio y Cloudflare Gateway\n\nAl 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](https://developers.cloudflare.com/monetization-gateway/x402/).\n\n| Aspecto | Método con Express de este artículo | Cloudflare Monetization Gateway |\n|---|---|---|\n| Procesamiento del pago del cliente | Middleware de Express | Gateway |\n| Punto de verificación del servidor de origen | Integración con el facilitator elegido | Verificación del JWT `PAYMENT-CONTEXT` |\n| Entrega del resultado de liquidación | `PAYMENT-RESPONSE` del middleware | Gateway genera el recibo de liquidación |\n| Comprobaciones adicionales | Cadenas admitidas y autenticación del facilitator | Verificación de la firma JWT y protección del acceso al origen |\n\n`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](https://developers.cloudflare.com/monetization-gateway/configuration/payment-validation/).\n\nAunque 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.\n\n## Distinción entre uso real y registros de liquidación\n\nEl 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.\n\n| Registro | Pregunta que permite responder | Registro adicional necesario |\n|---|---|---|\n| Respuesta 402 | Cuántas veces se han solicitado las condiciones de pago | Si el pago se ha producido realmente |\n| Verificación correcta | Si la autorización era válida | Resultado de liquidación |\n| Transferencia de USDC | Si se han movido los activos | Pedido al que corresponde |\n| Liquidación completada por pedido | Si se ha pagado la solicitud de pago | Estado de entrega de la respuesta |\n| Registro de reentrega | Si se ha recuperado una solicitud ya pagada | Identificador que permita distinguirla de un pago nuevo |\n\nDistinga 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.\n\n## Procedimiento de transición a la red principal de Base\n\nConsidere 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](https://docs.x402.org/getting-started/quickstart-for-sellers#running-on-mainnet).\n\n1. Compruebe que el facilitator elegido admita la red principal de Base.\n2. Compruebe en `/supported` la compatibilidad con v2, `exact` y `eip155:8453`.\n3. Configure la autenticación y las condiciones de uso exigidas por el proveedor.\n4. Cambie la red tanto en el servidor como en el cliente.\n5. Cambie la dirección permitida de USDC del cliente por la dirección de la red principal.\n6. Vuelva a contrastar el importe de la respuesta 402 y la dirección receptora real.\n7. Integre el almacenamiento para solicitudes duplicadas y el procedimiento de recuperación ante fallos.\n8. Complete la revisión de seguridad de las dependencias de producción.\n9. Compruebe la transferencia real y la entrega del contenido con el importe pequeño configurado.\n\nLa 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](https://docs.x402.org/core-concepts/network-and-token-support).","content_html":"\u003cp\u003eLos 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.\u003c/p\u003e\n\u003cp\u003eLa información sobre importes y cadenas se basa en la documentación oficial de x402, Base y Circle enlazada como fuente.\u003c/p\u003e\n\u003ch2\u003e\n\u003ca href=\"#preparaci%C3%B3n-e-instalaci%C3%B3n-para-la-pr%C3%A1ctica\" class=\"anchor\" id=\"preparación-e-instalación-para-la-práctica\"\u003e\u003c/a\u003ePreparación e instalación para la práctica\u003c/h2\u003e\n\u003cp\u003ePrepare 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 \u003ca href=\"https://docs.x402.org/getting-started/quickstart-for-sellers\"\u003eguía oficial para vendedores\u003c/a\u003e.\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003ePrepare una dirección de cartera EVM para recibir los pagos.\u003c/li\u003e\n\u003cli\u003ePrepare otra cartera de prueba para hacer los pagos.\u003c/li\u003e\n\u003cli\u003eConsiga USDC de prueba de Base Sepolia para la cartera de pago.\u003c/li\u003e\n\u003cli\u003eCree el proyecto de práctica con los siguientes comandos.\u003c/li\u003e\n\u003cli\u003eGuarde los archivos TypeScript que aparecen más adelante en la misma carpeta.\u003c/li\u003e\n\u003c/ol\u003e\n\u003cpre\u003e\u003ccode\u003e\u003cspan\u003emkdir\u003c/span\u003e\u003cspan\u003e x402-demo\n\u003c/span\u003e\u003cspan\u003ecd\u003c/span\u003e\u003cspan\u003e x402-demo\n\u003c/span\u003e\u003cspan\u003enpm\u003c/span\u003e\u003cspan\u003e init\u003c/span\u003e\u003cspan\u003e -y\n\u003c/span\u003e\u003cspan\u003enpm\u003c/span\u003e\u003cspan\u003e pkg set type=module\n\u003c/span\u003e\u003cspan\u003enpm\u003c/span\u003e\u003cspan\u003e install\u003c/span\u003e\u003cspan\u003e --save-exact\u003c/span\u003e\u003cspan\u003e express@5.3.0 viem@2.57.12 @x402/core@2.28.0 @x402/express@2.28.0 @x402/evm@2.28.0 @x402/fetch@2.28.0\n\u003c/span\u003e\u003cspan\u003enpm\u003c/span\u003e\u003cspan\u003e install\u003c/span\u003e\u003cspan\u003e --save-dev --save-exact\u003c/span\u003e\u003cspan\u003e typescript tsx @types/node @types/express\n\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003eEl 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 \u003ca href=\"https://docs.x402.org/getting-started/quickstart-for-buyers\"\u003eguía oficial para compradores\u003c/a\u003e.\u003c/p\u003e\n\u003cp\u003eLa 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.\u003c/p\u003e\n\u003ch2\u003e\n\u003ca href=\"#comparaci%C3%B3n-entre-x402-v1-y-v2\" class=\"anchor\" id=\"comparación-entre-x402-v1-y-v2\"\u003e\u003c/a\u003eComparación entre x402 v1 y v2\u003c/h2\u003e\n\u003cp\u003eAl 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 \u003ca href=\"https://docs.x402.org/guides/migration-v1-to-v2\"\u003eguía oficial de migración\u003c/a\u003e.\u003c/p\u003e\n\u003cdiv class=\"overflow-x-auto\"\u003e\u003ctable\u003e\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth\u003eAspecto\u003c/th\u003e\n\u003cth\u003ev1\u003c/th\u003e\n\u003cth\u003ev2\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd data-label=\"Aspecto\"\u003eVersión del protocolo\u003c/td\u003e\n\u003ctd data-label=\"v1\"\u003e\u003ccode\u003ex402Version: 1\u003c/code\u003e\u003c/td\u003e\n\u003ctd data-label=\"v2\"\u003e\u003ccode\u003ex402Version: 2\u003c/code\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd data-label=\"Aspecto\"\u003eCondiciones de pago iniciales\u003c/td\u003e\n\u003ctd data-label=\"v1\"\u003eCuerpo JSON de la respuesta 402\u003c/td\u003e\n\u003ctd data-label=\"v2\"\u003eCabecera de respuesta \u003ccode\u003ePAYMENT-REQUIRED\u003c/code\u003e\n\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd data-label=\"Aspecto\"\u003eDatos de pago firmados\u003c/td\u003e\n\u003ctd data-label=\"v1\"\u003eCabecera de solicitud \u003ccode\u003eX-PAYMENT\u003c/code\u003e\n\u003c/td\u003e\n\u003ctd data-label=\"v2\"\u003eCabecera de solicitud \u003ccode\u003ePAYMENT-SIGNATURE\u003c/code\u003e\n\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd data-label=\"Aspecto\"\u003eResultado de la liquidación\u003c/td\u003e\n\u003ctd data-label=\"v1\"\u003eCabecera de respuesta \u003ccode\u003eX-PAYMENT-RESPONSE\u003c/code\u003e\n\u003c/td\u003e\n\u003ctd data-label=\"v2\"\u003eCabecera de respuesta \u003ccode\u003ePAYMENT-RESPONSE\u003c/code\u003e\n\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd data-label=\"Aspecto\"\u003eIdentificador de la red principal de Base\u003c/td\u003e\n\u003ctd data-label=\"v1\"\u003e\u003ccode\u003ebase\u003c/code\u003e\u003c/td\u003e\n\u003ctd data-label=\"v2\"\u003e\u003ccode\u003eeip155:8453\u003c/code\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd data-label=\"Aspecto\"\u003eIdentificador de Base Sepolia\u003c/td\u003e\n\u003ctd data-label=\"v1\"\u003e\u003ccode\u003ebase-sepolia\u003c/code\u003e\u003c/td\u003e\n\u003ctd data-label=\"v2\"\u003e\u003ccode\u003eeip155:84532\u003c/code\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd data-label=\"Aspecto\"\u003eCampo del importe en las condiciones de pago\u003c/td\u003e\n\u003ctd data-label=\"v1\"\u003e\u003ccode\u003emaxAmountRequired\u003c/code\u003e\u003c/td\u003e\n\u003ctd data-label=\"v2\"\u003e\u003ccode\u003eamount\u003c/code\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd data-label=\"Aspecto\"\u003eDescripción del recurso\u003c/td\u003e\n\u003ctd data-label=\"v1\"\u003e\n\u003ccode\u003eresource\u003c/code\u003e y otros campos dentro de las condiciones de pago\u003c/td\u003e\n\u003ctd data-label=\"v2\"\u003eObjeto \u003ccode\u003eresource\u003c/code\u003e de nivel superior\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd data-label=\"Aspecto\"\u003eCondiciones en los datos de pago\u003c/td\u003e\n\u003ctd data-label=\"v1\"\u003e\n\u003ccode\u003escheme\u003c/code\u003e, \u003ccode\u003enetwork\u003c/code\u003e y otros campos de nivel superior\u003c/td\u003e\n\u003ctd data-label=\"v2\"\u003eObjeto \u003ccode\u003eaccepted\u003c/code\u003e que contiene las condiciones seleccionadas\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd data-label=\"Aspecto\"\u003eEjemplo de paquete TypeScript\u003c/td\u003e\n\u003ctd data-label=\"v1\"\u003e\u003ccode\u003ex402-express\u003c/code\u003e\u003c/td\u003e\n\u003ctd data-label=\"v2\"\u003e\u003ccode\u003e@x402/express\u003c/code\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\u003c/div\u003e\n\u003cp\u003eLa ubicación donde se envían las condiciones de pago en v1 está especificada en la \u003ca href=\"https://github.com/x402-foundation/x402/blob/main/specs/transports-v1/http.md\"\u003eespecificación HTTP v1\u003c/a\u003e. La ubicación estándar en v2 es la cabecera \u003ccode\u003ePAYMENT-REQUIRED\u003c/code\u003e. Una implementación también puede devolverlas en el cuerpo, pero debe procesarlas tomando la cabecera como referencia.\u003c/p\u003e\n\u003cp\u003eLa \u003ca href=\"https://github.com/x402-foundation/x402/blob/main/specs/transports-v2/http.md\"\u003eespecificación HTTP v2\u003c/a\u003e describe el código de estado de la siguiente manera.\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003eEl servidor indica que se requiere un pago mediante el código de estado HTTP 402 «Payment Required».\u003c/p\u003e\n\u003cp\u003eFuente: especificación HTTP v2 de x402\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003eLas cabeceras de pago de v2 contienen JSON codificado en Base64. Base64 no es un método de cifrado. Use HTTPS en los servicios externos.\u003c/p\u003e\n\u003ch2\u003e\n\u003ca href=\"#solicitud-http-402-y-secuencia-de-pago\" class=\"anchor\" id=\"solicitud-http-402-y-secuencia-de-pago\"\u003e\u003c/a\u003eSolicitud HTTP 402 y secuencia de pago\u003c/h2\u003e\n\u003cp\u003eEsta práctica utiliza el flujo de autorización predeterminado del esquema EVM \u003ccode\u003eexact\u003c/code\u003e. \u003ccode\u003eexact\u003c/code\u003e es un esquema para pagar un importe fijo. La secuencia sigue la \u003ca href=\"https://github.com/x402-foundation/x402/blob/main/specs/x402-specification-v2.md\"\u003eespecificación principal de x402 v2\u003c/a\u003e.\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003eEl cliente solicita la API de pago sin información de pago.\u003c/li\u003e\n\u003cli\u003eEl servidor devuelve HTTP 402 y \u003ccode\u003ePAYMENT-REQUIRED\u003c/code\u003e.\u003c/li\u003e\n\u003cli\u003eEl cliente selecciona unas condiciones permitidas de \u003ccode\u003eaccepts\u003c/code\u003e.\u003c/li\u003e\n\u003cli\u003eEl SDK firma una autorización de pago que cumple las condiciones seleccionadas.\u003c/li\u003e\n\u003cli\u003eEl cliente repite la solicitud añadiendo \u003ccode\u003ePAYMENT-SIGNATURE\u003c/code\u003e.\u003c/li\u003e\n\u003cli\u003eEl servidor verifica la autorización mediante \u003ccode\u003e/verify\u003c/code\u003e del facilitator.\u003c/li\u003e\n\u003cli\u003eSi la verificación se supera, el servidor procesa el recurso.\u003c/li\u003e\n\u003cli\u003eEl servidor solicita la liquidación mediante \u003ccode\u003e/settle\u003c/code\u003e.\u003c/li\u003e\n\u003cli\u003eTras una liquidación correcta, entrega el cuerpo de pago y \u003ccode\u003ePAYMENT-RESPONSE\u003c/code\u003e.\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003eEsta 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 \u003ccode\u003eauthorization\u003c/code\u003e.\u003c/p\u003e\n\u003ch3\u003e\n\u003ca href=\"#funciones-del-servidor-de-recursos-y-del-facilitator\" class=\"anchor\" id=\"funciones-del-servidor-de-recursos-y-del-facilitator\"\u003e\u003c/a\u003eFunciones del servidor de recursos y del facilitator\u003c/h3\u003e\n\u003cp\u003eEl 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 \u003ca href=\"https://github.com/x402-foundation/x402/blob/main/docs/core-concepts/facilitator.md\"\u003edocumentación oficial del facilitator\u003c/a\u003e.\u003c/p\u003e\n\u003cdiv class=\"overflow-x-auto\"\u003e\u003ctable\u003e\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth\u003eComponente\u003c/th\u003e\n\u003cth\u003eFunción\u003c/th\u003e\n\u003cth\u003eEstado que no debe considerarse un éxito\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd data-label=\"Componente\"\u003eCliente\u003c/td\u003e\n\u003ctd data-label=\"Función\"\u003eSeleccionar las condiciones y firmar la autorización de pago\u003c/td\u003e\n\u003ctd data-label=\"Estado que no debe considerarse un éxito\"\u003eSolo se ha generado la firma\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd data-label=\"Componente\"\u003eServidor de recursos\u003c/td\u003e\n\u003ctd data-label=\"Función\"\u003eDeclarar el precio y controlar la respuesta de pago\u003c/td\u003e\n\u003ctd data-label=\"Estado que no debe considerarse un éxito\"\u003eEl cliente afirma que el pago se ha completado\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd data-label=\"Componente\"\u003eFacilitator \u003ccode\u003e/verify\u003c/code\u003e\n\u003c/td\u003e\n\u003ctd data-label=\"Función\"\u003eComprobar la validez de la firma y de las condiciones de pago\u003c/td\u003e\n\u003ctd data-label=\"Estado que no debe considerarse un éxito\"\u003eSolo se ha recibido \u003ccode\u003eisValid: true\u003c/code\u003e\n\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd data-label=\"Componente\"\u003eFacilitator \u003ccode\u003e/settle\u003c/code\u003e\n\u003c/td\u003e\n\u003ctd data-label=\"Función\"\u003eEn esta práctica, ejecutar el pago en la cadena y devolver el resultado\u003c/td\u003e\n\u003ctd data-label=\"Estado que no debe considerarse un éxito\"\u003eSe ha enviado, pero no se ha confirmado el resultado\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\u003c/div\u003e\n\u003cp\u003e\u003ccode\u003e/verify\u003c/code\u003e 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.\u003c/p\u003e\n\u003cp\u003eBloquee 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 \u003ca href=\"https://github.com/x402-foundation/x402/blob/main/typescript/packages/http/express/src/index.ts\"\u003eimplementación oficial de Express\u003c/a\u003e.\u003c/p\u003e\n\u003ch2\u003e\n\u003ca href=\"#comparaci%C3%B3n-entre-la-red-principal-y-la-red-de-prueba-de-base\" class=\"anchor\" id=\"comparación-entre-la-red-principal-y-la-red-de-prueba-de-base\"\u003e\u003c/a\u003eComparación entre la red principal y la red de prueba de Base\u003c/h2\u003e\n\u003cp\u003eEn 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 \u003ca href=\"https://developers.circle.com/stablecoins/usdc-contract-addresses\"\u003elista de contratos de USDC de Circle\u003c/a\u003e.\u003c/p\u003e\n\u003cdiv class=\"overflow-x-auto\"\u003e\u003ctable\u003e\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth\u003eAspecto\u003c/th\u003e\n\u003cth\u003eRed principal de Base\u003c/th\u003e\n\u003cth\u003eRed de prueba Base Sepolia\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd data-label=\"Aspecto\"\u003eUso\u003c/td\u003e\n\u003ctd data-label=\"Red principal de Base\"\u003ePagos con activos reales\u003c/td\u003e\n\u003ctd data-label=\"Red de prueba Base Sepolia\"\u003ePruebas de implementación y gestión de fallos\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd data-label=\"Aspecto\"\u003eChain ID\u003c/td\u003e\n\u003ctd data-label=\"Red principal de Base\"\u003e\u003ccode\u003e8453\u003c/code\u003e\u003c/td\u003e\n\u003ctd data-label=\"Red de prueba Base Sepolia\"\u003e\u003ccode\u003e84532\u003c/code\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd data-label=\"Aspecto\"\u003eRed x402 v2\u003c/td\u003e\n\u003ctd data-label=\"Red principal de Base\"\u003e\u003ccode\u003eeip155:8453\u003c/code\u003e\u003c/td\u003e\n\u003ctd data-label=\"Red de prueba Base Sepolia\"\u003e\u003ccode\u003eeip155:84532\u003c/code\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd data-label=\"Aspecto\"\u003eContrato de USDC\u003c/td\u003e\n\u003ctd data-label=\"Red principal de Base\"\u003e\u003ccode\u003e0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913\u003c/code\u003e\u003c/td\u003e\n\u003ctd data-label=\"Red de prueba Base Sepolia\"\u003e\u003ccode\u003e0x036CbD53842c5426634e7929541eC2318f3dCF7e\u003c/code\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd data-label=\"Aspecto\"\u003eRPC público\u003c/td\u003e\n\u003ctd data-label=\"Red principal de Base\"\u003e\u003ccode\u003ehttps://mainnet.base.org\u003c/code\u003e\u003c/td\u003e\n\u003ctd data-label=\"Red de prueba Base Sepolia\"\u003e\u003ccode\u003ehttps://sepolia.base.org\u003c/code\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd data-label=\"Aspecto\"\u003eValor financiero del token\u003c/td\u003e\n\u003ctd data-label=\"Red principal de Base\"\u003eActivo con valor financiero real\u003c/td\u003e\n\u003ctd data-label=\"Red de prueba Base Sepolia\"\u003eSin valor financiero\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\u003c/div\u003e\n\u003cp\u003eConsulte el Chain ID y el RPC en la \u003ca href=\"https://docs.base.org/get-started/connect-to-base\"\u003edocumentación de la red Base\u003c/a\u003e. 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.\u003c/p\u003e\n\u003cp\u003ePuede solicitar USDC de prueba en \u003ca href=\"https://faucet.circle.com/\"\u003eCircle Testnet Faucet\u003c/a\u003e. 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.\u003c/p\u003e\n\u003ch2\u003e\n\u003ca href=\"#implementaci%C3%B3n-de-una-api-de-pago-con-nodejs\" class=\"anchor\" id=\"implementación-de-una-api-de-pago-con-nodejs\"\u003e\u003c/a\u003eImplementación de una API de pago con Node.js\u003c/h2\u003e\n\u003cp\u003eConecte \u003ccode\u003epaymentMiddleware\u003c/code\u003e antes de la ruta de pago. El siguiente ejemplo exige \u003cstrong\u003e0.001 USDC\u003c/strong\u003e 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)\u003c/p\u003e\n\u003ch3\u003e\n\u003ca href=\"#archivo-del-servidor\" class=\"anchor\" id=\"archivo-del-servidor\"\u003e\u003c/a\u003eArchivo del servidor\u003c/h3\u003e\n\u003cp\u003eGuarde el siguiente código como \u003ccode\u003eserver.ts\u003c/code\u003e. El servidor solo acepta solicitudes en la interfaz local. La dirección receptora se lee de la variable de entorno \u003ccode\u003ePAY_TO\u003c/code\u003e.\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e\u003cspan\u003eimport express from \"express\";\n\u003c/span\u003e\u003cspan\u003eimport { getAddress, zeroAddress } from \"viem\";\n\u003c/span\u003e\u003cspan\u003eimport { paymentMiddleware } from \"@x402/express\";\n\u003c/span\u003e\u003cspan\u003eimport { HTTPFacilitatorClient, x402ResourceServer } from \"@x402/core/server\";\n\u003c/span\u003e\u003cspan\u003eimport { ExactEvmScheme } from \"@x402/evm/exact/server\";\n\u003c/span\u003e\u003cspan\u003e\n\u003c/span\u003e\u003cspan\u003econst payTo = getAddress(process.env.PAY_TO ?? \"\");\n\u003c/span\u003e\u003cspan\u003eif (payTo === zeroAddress) throw new Error(\"Invalid payTo\");\n\u003c/span\u003e\u003cspan\u003econst network = \"eip155:84532\";\n\u003c/span\u003e\u003cspan\u003econst resourceServer = new x402ResourceServer(\n\u003c/span\u003e\u003cspan\u003e  new HTTPFacilitatorClient({ url: \"https://x402.org/facilitator\" }),\n\u003c/span\u003e\u003cspan\u003e).register(network, new ExactEvmScheme());\n\u003c/span\u003e\u003cspan\u003e\n\u003c/span\u003e\u003cspan\u003econst app = express();\n\u003c/span\u003e\u003cspan\u003eapp.use((_req, res, next) =\u0026gt; {\n\u003c/span\u003e\u003cspan\u003e  res.setHeader(\"Cache-Control\", \"private, no-store\");\n\u003c/span\u003e\u003cspan\u003e  next();\n\u003c/span\u003e\u003cspan\u003e});\n\u003c/span\u003e\u003cspan\u003eapp.use(paymentMiddleware({\n\u003c/span\u003e\u003cspan\u003e  \"GET /paid-data\": {\n\u003c/span\u003e\u003cspan\u003e    accepts: [{ scheme: \"exact\", price: \"$0.001\", network, payTo }],\n\u003c/span\u003e\u003cspan\u003e    description: \"Sample paid JSON\",\n\u003c/span\u003e\u003cspan\u003e    mimeType: \"application/json\",\n\u003c/span\u003e\u003cspan\u003e  },\n\u003c/span\u003e\u003cspan\u003e}, resourceServer));\n\u003c/span\u003e\u003cspan\u003eapp.get(\"/paid-data\", (_req, res) =\u0026gt; {\n\u003c/span\u003e\u003cspan\u003e  res.json({ content: \"Paid sample content\" });\n\u003c/span\u003e\u003cspan\u003e});\n\u003c/span\u003e\u003cspan\u003eapp.listen(4021, \"127.0.0.1\");\n\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e\u003ccode\u003ehttps://x402.org/facilitator\u003c/code\u003e 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 \u003ca href=\"https://docs.x402.org/getting-started/quickstart-for-sellers#running-on-mainnet\"\u003eprocedimiento para la red principal de la guía para vendedores\u003c/a\u003e.\u003c/p\u003e\n\u003ch3\u003e\n\u003ca href=\"#ejemplo-de-c%C3%A1lculo-del-precio\" class=\"anchor\" id=\"ejemplo-de-cálculo-del-precio\"\u003e\u003c/a\u003eEjemplo de cálculo del precio\u003c/h3\u003e\n\u003cp\u003eEl precio del ejemplo equivale a \u003ccode\u003e1000\u003c/code\u003e unidades mínimas de USDC. USDC tiene 6 decimales. La conversión de precios del SDK se basa en la \u003ca href=\"https://github.com/x402-foundation/x402/blob/main/typescript/packages/mechanisms/evm/src/exact/server/scheme.ts\"\u003eimplementación del servidor EVM\u003c/a\u003e.\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e\u003cspan\u003e0.001 USDC × 10^6 = 1000 최소 단위\n\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\n\u003cdiv class=\"overflow-x-auto\"\u003e\u003ctable\u003e\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth\u003eValor que debe comprobarse\u003c/th\u003e\n\u003cth\u003eValor esperado en este ejemplo\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd data-label=\"Valor que debe comprobarse\"\u003e\n\u003ccode\u003eprice\u003c/code\u003e en la configuración del servidor\u003c/td\u003e\n\u003ctd data-label=\"Valor esperado en este ejemplo\"\u003e\u003ccode\u003e\"$0.001\"\u003c/code\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd data-label=\"Valor que debe comprobarse\"\u003e\n\u003ccode\u003eamount\u003c/code\u003e en las condiciones de pago del 402\u003c/td\u003e\n\u003ctd data-label=\"Valor esperado en este ejemplo\"\u003e\u003ccode\u003e\"1000\"\u003c/code\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd data-label=\"Valor que debe comprobarse\"\u003e\n\u003ccode\u003easset\u003c/code\u003e en las condiciones de pago\u003c/td\u003e\n\u003ctd data-label=\"Valor esperado en este ejemplo\"\u003eContrato de USDC de Base Sepolia\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd data-label=\"Valor que debe comprobarse\"\u003e\n\u003ccode\u003epayTo\u003c/code\u003e en las condiciones de pago\u003c/td\u003e\n\u003ctd data-label=\"Valor esperado en este ejemplo\"\u003eDirección receptora configurada\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd data-label=\"Valor que debe comprobarse\"\u003e\n\u003ccode\u003enetwork\u003c/code\u003e en las condiciones de pago\u003c/td\u003e\n\u003ctd data-label=\"Valor esperado en este ejemplo\"\u003e\u003ccode\u003eeip155:84532\u003c/code\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\u003c/div\u003e\n\u003cp\u003e\u003ccode\u003eprice\u003c/code\u003e es un valor de configuración del SDK. En las condiciones de pago reales de v2 se envía \u003ccode\u003eamount\u003c/code\u003e. Compare los importes enteros como cadenas de texto o como \u003ccode\u003ebigint\u003c/code\u003e.\u003c/p\u003e\n\u003ch3\u003e\n\u003ca href=\"#ejecuci%C3%B3n-del-servidor-y-comprobaci%C3%B3n-del-402\" class=\"anchor\" id=\"ejecución-del-servidor-y-comprobación-del-402\"\u003e\u003c/a\u003eEjecución del servidor y comprobación del 402\u003c/h3\u003e\n\u003cp\u003eEjecute 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.\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e\u003cspan\u003eread \u003c/span\u003e\u003cspan\u003e-r -p \u003c/span\u003e\u003cspan\u003e'\u003c/span\u003e\u003cspan\u003e수취 지갑 주소: \u003c/span\u003e\u003cspan\u003e' PAY_TO\n\u003c/span\u003e\u003cspan\u003eexport \u003c/span\u003e\u003cspan\u003ePAY_TO\n\u003c/span\u003e\u003cspan\u003enpx\u003c/span\u003e\u003cspan\u003e tsx server.ts\n\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003eEnví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.\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e\u003cspan\u003enode\u003c/span\u003e\u003cspan\u003e --input-type\u003c/span\u003e\u003cspan\u003e=module \u0026lt;\u0026lt;'\u003c/span\u003e\u003cspan\u003eJS\u003c/span\u003e\u003cspan\u003e'\n\u003c/span\u003e\u003cspan\u003econst response = await fetch(\"http://127.0.0.1:4021/paid-data\");\n\u003c/span\u003e\u003cspan\u003econst header = response.headers.get(\"PAYMENT-REQUIRED\");\n\u003c/span\u003e\u003cspan\u003econsole.log(response.status);\n\u003c/span\u003e\u003cspan\u003econsole.log(header \u0026amp;\u0026amp; JSON.parse(\n\u003c/span\u003e\u003cspan\u003e  Buffer.from(header, \"base64\").toString(\"utf8\")\n\u003c/span\u003e\u003cspan\u003e));\n\u003c/span\u003e\u003cspan\u003eJS\n\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003eLa 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.\u003c/p\u003e\n\u003ch2\u003e\n\u003ca href=\"#selecci%C3%B3n-de-condiciones-de-pago-e-implementaci%C3%B3n-del-cliente\" class=\"anchor\" id=\"selección-de-condiciones-de-pago-e-implementación-del-cliente\"\u003e\u003c/a\u003eSelección de condiciones de pago e implementación del cliente\u003c/h2\u003e\n\u003cp\u003eRestrinja 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 \u003ccode\u003eregisterPolicy\u003c/code\u003e de la \u003ca href=\"https://github.com/x402-foundation/x402/blob/main/typescript/packages/core/src/client/x402Client.ts\"\u003eimplementación oficial de x402Client\u003c/a\u003e.\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003eGuarde el siguiente código como \u003ccode\u003eclient.ts\u003c/code\u003e.\u003c/li\u003e\n\u003cli\u003eGuarde también \u003ccode\u003echeck-transfer.ts\u003c/code\u003e, que aparece en la siguiente sección.\u003c/li\u003e\n\u003cli\u003eUna vez preparados ambos archivos, continúe con el procedimiento de ejecución.\u003c/li\u003e\n\u003c/ol\u003e\n\u003cpre\u003e\u003ccode\u003e\u003cspan\u003eimport { writeFile } from \"node:fs/promises\";\n\u003c/span\u003e\u003cspan\u003eimport { getAddress, zeroAddress, type Hex, type Hash } from \"viem\";\n\u003c/span\u003e\u003cspan\u003eimport { privateKeyToAccount } from \"viem/accounts\";\n\u003c/span\u003e\u003cspan\u003eimport { x402Client, wrapFetchWithPayment } from \"@x402/fetch\";\n\u003c/span\u003e\u003cspan\u003eimport { decodePaymentResponseHeader } from \"@x402/core/http\";\n\u003c/span\u003e\u003cspan\u003eimport { ExactEvmScheme } from \"@x402/evm/exact/client\";\n\u003c/span\u003e\u003cspan\u003eimport { checkTransfer } from \"./check-transfer.js\";\n\u003c/span\u003e\u003cspan\u003e\n\u003c/span\u003e\u003cspan\u003econst key = process.env.EVM_PRIVATE_KEY ?? \"\";\n\u003c/span\u003e\u003cspan\u003eif (!/^0x[0-9a-fA-F]{64}$/.test(key)) throw new Error(\"Invalid test key\");\n\u003c/span\u003e\u003cspan\u003econst signer = privateKeyToAccount(key as Hex);\n\u003c/span\u003e\u003cspan\u003econst payTo = getAddress(process.env.PAY_TO ?? \"\");\n\u003c/span\u003e\u003cspan\u003eif (payTo === zeroAddress) throw new Error(\"Invalid payTo\");\n\u003c/span\u003e\u003cspan\u003econst network = \"eip155:84532\";\n\u003c/span\u003e\u003cspan\u003econst token = \"0x036CbD53842c5426634e7929541eC2318f3dCF7e\";\n\u003c/span\u003e\u003cspan\u003econst client = new x402Client().register(network, new ExactEvmScheme(signer));\n\u003c/span\u003e\u003cspan\u003eclient.registerPolicy((version, options) =\u0026gt; version === 2\n\u003c/span\u003e\u003cspan\u003e  ? options.filter(r =\u0026gt;\n\u003c/span\u003e\u003cspan\u003e      r.scheme === \"exact\" \u0026amp;\u0026amp; r.network === network \u0026amp;\u0026amp;\n\u003c/span\u003e\u003cspan\u003e      r.asset.toLowerCase() === token.toLowerCase() \u0026amp;\u0026amp;\n\u003c/span\u003e\u003cspan\u003e      r.payTo.toLowerCase() === payTo.toLowerCase() \u0026amp;\u0026amp; r.amount === \"1000\" \u0026amp;\u0026amp;\n\u003c/span\u003e\u003cspan\u003e      (!r.extra?.assetTransferMethod || r.extra.assetTransferMethod === \"eip3009\") \u0026amp;\u0026amp;\n\u003c/span\u003e\u003cspan\u003e      (!r.extra?.paymentFlow || r.extra.paymentFlow === \"authorization\"))\n\u003c/span\u003e\u003cspan\u003e  : []);\n\u003c/span\u003e\u003cspan\u003e\n\u003c/span\u003e\u003cspan\u003econst paidFetch = wrapFetchWithPayment(fetch, client);\n\u003c/span\u003e\u003cspan\u003econst response = await paidFetch(\"http://127.0.0.1:4021/paid-data\", {\n\u003c/span\u003e\u003cspan\u003e  redirect: \"error\",\n\u003c/span\u003e\u003cspan\u003e});\n\u003c/span\u003e\u003cspan\u003econst raw = response.headers.get(\"PAYMENT-RESPONSE\");\n\u003c/span\u003e\u003cspan\u003eif (!raw) throw new Error(`No settlement receipt: HTTP ${response.status}`);\n\u003c/span\u003e\u003cspan\u003econst settlement = decodePaymentResponseHeader(raw);\n\u003c/span\u003e\u003cspan\u003eawait writeFile(\"settlement.json\", JSON.stringify(settlement, null, 2));\n\u003c/span\u003e\u003cspan\u003eif (!response.ok || !settlement.success || settlement.network !== network) {\n\u003c/span\u003e\u003cspan\u003e  throw new Error(\"Payment unresolved; inspect settlement.json before retrying\");\n\u003c/span\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003cspan\u003econst evidence = await checkTransfer(\n\u003c/span\u003e\u003cspan\u003e  network, settlement.transaction as Hash, signer.address, payTo, 1000n,\n\u003c/span\u003e\u003cspan\u003e);\n\u003c/span\u003e\u003cspan\u003eawait writeFile(\"transfer.json\", JSON.stringify(evidence, null, 2));\n\u003c/span\u003e\u003cspan\u003econsole.log(await response.text());\n\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e\u003ccode\u003ewrapFetchWithPayment\u003c/code\u003e se encarga de procesar el 402 y de repetir la solicitud con la firma. Su uso sigue el \u003ca href=\"https://github.com/x402-foundation/x402/tree/main/examples/typescript/clients/fetch\"\u003eejemplo oficial de fetch\u003c/a\u003e. Si no hay condiciones de pago permitidas, se detiene la creación del pago.\u003c/p\u003e\n\u003cp\u003eEste 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.\u003c/p\u003e\n\u003ch2\u003e\n\u003ca href=\"#verificaci%C3%B3n-del-evento-transfer-de-usdc\" class=\"anchor\" id=\"verificación-del-evento-transfer-de-usdc\"\u003e\u003c/a\u003eVerificación del evento Transfer de USDC\u003c/h2\u003e\n\u003cp\u003eCompruebe 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 \u003ccode\u003eTransfer\u003c/code\u003e se basan en el \u003ca href=\"https://eips.ethereum.org/EIPS/eip-20\"\u003eestándar ERC-20\u003c/a\u003e.\u003c/p\u003e\n\u003cp\u003eLa verificación requiere los siguientes elementos.\u003c/p\u003e\n\u003cdiv class=\"overflow-x-auto\"\u003e\u003ctable\u003e\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth\u003eElemento de verificación\u003c/th\u003e\n\u003cth\u003eValor con el que se compara\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd data-label=\"Elemento de verificación\"\u003eChain ID del RPC\u003c/td\u003e\n\u003ctd data-label=\"Valor con el que se compara\"\u003eCadena permitida por el servidor\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd data-label=\"Elemento de verificación\"\u003e\n\u003ccode\u003estatus\u003c/code\u003e del recibo de la transacción\u003c/td\u003e\n\u003ctd data-label=\"Valor con el que se compara\"\u003eEstado correcto\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd data-label=\"Elemento de verificación\"\u003eDirección que emitió el evento\u003c/td\u003e\n\u003ctd data-label=\"Valor con el que se compara\"\u003eContrato oficial de USDC de esa cadena\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd data-label=\"Elemento de verificación\"\u003e\u003ccode\u003eTransfer.from\u003c/code\u003e\u003c/td\u003e\n\u003ctd data-label=\"Valor con el que se compara\"\u003ePagador confirmado\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd data-label=\"Elemento de verificación\"\u003e\u003ccode\u003eTransfer.to\u003c/code\u003e\u003c/td\u003e\n\u003ctd data-label=\"Valor con el que se compara\"\u003eDirección receptora definida por el servidor\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd data-label=\"Elemento de verificación\"\u003e\u003ccode\u003eTransfer.value\u003c/code\u003e\u003c/td\u003e\n\u003ctd data-label=\"Valor con el que se compara\"\u003eImporte exigido por el servidor en unidades mínimas\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\u003c/div\u003e\n\u003cp\u003eGuarde el siguiente código como \u003ccode\u003echeck-transfer.ts\u003c/code\u003e. La consulta utiliza \u003ca href=\"https://viem.sh/docs/actions/public/getTransactionReceipt\"\u003egetTransactionReceipt\u003c/a\u003e de viem. La interpretación de los eventos se basa en \u003ca href=\"https://viem.sh/docs/contract/parseEventLogs\"\u003eparseEventLogs\u003c/a\u003e.\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e\u003cspan\u003eimport {\n\u003c/span\u003e\u003cspan\u003e  createPublicClient, http, getAddress, parseEventLogs,\n\u003c/span\u003e\u003cspan\u003e  erc20Abi, type Address, type Hash,\n\u003c/span\u003e\u003cspan\u003e} from \"viem\";\n\u003c/span\u003e\u003cspan\u003eimport { base, baseSepolia } from \"viem/chains\";\n\u003c/span\u003e\u003cspan\u003e\n\u003c/span\u003e\u003cspan\u003econst configs = {\n\u003c/span\u003e\u003cspan\u003e  \"eip155:84532\": {\n\u003c/span\u003e\u003cspan\u003e    chain: baseSepolia,\n\u003c/span\u003e\u003cspan\u003e    rpc: \"https://sepolia.base.org\",\n\u003c/span\u003e\u003cspan\u003e    token: \"0x036CbD53842c5426634e7929541eC2318f3dCF7e\",\n\u003c/span\u003e\u003cspan\u003e  },\n\u003c/span\u003e\u003cspan\u003e  \"eip155:8453\": {\n\u003c/span\u003e\u003cspan\u003e    chain: base,\n\u003c/span\u003e\u003cspan\u003e    rpc: \"https://mainnet.base.org\",\n\u003c/span\u003e\u003cspan\u003e    token: \"0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913\",\n\u003c/span\u003e\u003cspan\u003e  },\n\u003c/span\u003e\u003cspan\u003e} as const;\n\u003c/span\u003e\u003cspan\u003e\n\u003c/span\u003e\u003cspan\u003eexport async function checkTransfer(\n\u003c/span\u003e\u003cspan\u003e  network: keyof typeof configs, hash: Hash,\n\u003c/span\u003e\u003cspan\u003e  payer: Address, payTo: Address, amount: bigint,\n\u003c/span\u003e\u003cspan\u003e) {\n\u003c/span\u003e\u003cspan\u003e  const cfg = configs[network];\n\u003c/span\u003e\u003cspan\u003e  const rpc = createPublicClient({ chain: cfg.chain, transport: http(cfg.rpc) });\n\u003c/span\u003e\u003cspan\u003e  if (await rpc.getChainId() !== cfg.chain.id) throw new Error(\"Wrong chain\");\n\u003c/span\u003e\u003cspan\u003e  const receipt = await rpc.getTransactionReceipt({ hash });\n\u003c/span\u003e\u003cspan\u003e  if (receipt.status !== \"success\") throw new Error(\"Transaction failed\");\n\u003c/span\u003e\u003cspan\u003e  const logs = parseEventLogs({\n\u003c/span\u003e\u003cspan\u003e    abi: erc20Abi,\n\u003c/span\u003e\u003cspan\u003e    eventName: \"Transfer\",\n\u003c/span\u003e\u003cspan\u003e    logs: receipt.logs.filter(\n\u003c/span\u003e\u003cspan\u003e      log =\u0026gt; getAddress(log.address) === getAddress(cfg.token),\n\u003c/span\u003e\u003cspan\u003e    ),\n\u003c/span\u003e\u003cspan\u003e    strict: true,\n\u003c/span\u003e\u003cspan\u003e  });\n\u003c/span\u003e\u003cspan\u003e  const transfer = logs.find(log =\u0026gt;\n\u003c/span\u003e\u003cspan\u003e    getAddress(log.args.from) === getAddress(payer) \u0026amp;\u0026amp;\n\u003c/span\u003e\u003cspan\u003e    getAddress(log.args.to) === getAddress(payTo) \u0026amp;\u0026amp;\n\u003c/span\u003e\u003cspan\u003e    log.args.value === amount,\n\u003c/span\u003e\u003cspan\u003e  );\n\u003c/span\u003e\u003cspan\u003e  if (!transfer) throw new Error(\"Matching USDC Transfer not found\");\n\u003c/span\u003e\u003cspan\u003e  return {\n\u003c/span\u003e\u003cspan\u003e    network, transaction: hash, logIndex: transfer.logIndex,\n\u003c/span\u003e\u003cspan\u003e    blockHash: receipt.blockHash, blockNumber: receipt.blockNumber.toString(),\n\u003c/span\u003e\u003cspan\u003e  };\n\u003c/span\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003eEsta 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.\u003c/p\u003e\n\u003cp\u003eNo confíe en el archivo \u003ccode\u003etransfer.json\u003c/code\u003e 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.\u003c/p\u003e\n\u003cp\u003eUn 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.\u003c/p\u003e\n\u003ch2\u003e\n\u003ca href=\"#ejecuci%C3%B3n-del-pago-de-prueba-y-comprobaci%C3%B3n-de-resultados\" class=\"anchor\" id=\"ejecución-del-pago-de-prueba-y-comprobación-de-resultados\"\u003e\u003c/a\u003eEjecución del pago de prueba y comprobación de resultados\u003c/h2\u003e\n\u003cp\u003eDespué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.\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003eCompruebe los tipos con el siguiente comando.\u003c/li\u003e\n\u003cli\u003eIntroduzca en el segundo terminal la misma dirección receptora que usa el servidor.\u003c/li\u003e\n\u003cli\u003eIntroduzca la clave privada de la cartera de pago de prueba sin que se muestre en pantalla.\u003c/li\u003e\n\u003cli\u003eEjecute el cliente una vez.\u003c/li\u003e\n\u003cli\u003eCompruebe el resultado de liquidación y los registros de transferencia guardados.\u003c/li\u003e\n\u003c/ol\u003e\n\u003cpre\u003e\u003ccode\u003e\u003cspan\u003enpx\u003c/span\u003e\u003cspan\u003e tsc\u003c/span\u003e\u003cspan\u003e --noEmit --strict --skipLibCheck --target\u003c/span\u003e\u003cspan\u003e ES2022\u003c/span\u003e\u003cspan\u003e --module\u003c/span\u003e\u003cspan\u003e NodeNext\u003c/span\u003e\u003cspan\u003e --moduleResolution\u003c/span\u003e\u003cspan\u003e NodeNext server.ts client.ts check-transfer.ts\n\u003c/span\u003e\u003cspan\u003eread \u003c/span\u003e\u003cspan\u003e-r -p \u003c/span\u003e\u003cspan\u003e'\u003c/span\u003e\u003cspan\u003e같은 수취 지갑 주소: \u003c/span\u003e\u003cspan\u003e' PAY_TO\n\u003c/span\u003e\u003cspan\u003eread \u003c/span\u003e\u003cspan\u003e-r -s -p \u003c/span\u003e\u003cspan\u003e'\u003c/span\u003e\u003cspan\u003e테스트 결제 지갑 개인키: \u003c/span\u003e\u003cspan\u003e' EVM_PRIVATE_KEY\n\u003c/span\u003e\u003cspan\u003eexport \u003c/span\u003e\u003cspan\u003ePAY_TO EVM_PRIVATE_KEY\n\u003c/span\u003e\u003cspan\u003enpx\u003c/span\u003e\u003cspan\u003e tsx client.ts\n\u003c/span\u003e\u003cspan\u003eunset\u003c/span\u003e\u003cspan\u003e EVM_PRIVATE_KEY\n\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\n\u003cdiv class=\"overflow-x-auto\"\u003e\u003ctable\u003e\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth\u003eResultado\u003c/th\u003e\n\u003cth\u003eSignificado\u003c/th\u003e\n\u003cth\u003eQué comprobar\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd data-label=\"Resultado\"\u003e\u003ccode\u003esettlement.json\u003c/code\u003e\u003c/td\u003e\n\u003ctd data-label=\"Significado\"\u003eResultado de liquidación devuelto por el servidor\u003c/td\u003e\n\u003ctd data-label=\"Qué comprobar\"\u003e\n\u003ccode\u003esuccess\u003c/code\u003e, \u003ccode\u003enetwork\u003c/code\u003e, \u003ccode\u003etransaction\u003c/code\u003e\n\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd data-label=\"Resultado\"\u003e\u003ccode\u003etransfer.json\u003c/code\u003e\u003c/td\u003e\n\u003ctd data-label=\"Significado\"\u003eRegistro de transferencia encontrado en la consulta RPC\u003c/td\u003e\n\u003ctd data-label=\"Qué comprobar\"\u003eCadena, hash de transacción, posición del registro e información del bloque\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd data-label=\"Resultado\"\u003eCuerpo de pago en la consola\u003c/td\u003e\n\u003ctd data-label=\"Significado\"\u003eDatos mostrados tras la verificación de este cliente\u003c/td\u003e\n\u003ctd data-label=\"Qué comprobar\"\u003eComprobar que sea el contenido solicitado\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\u003c/div\u003e\n\u003cp\u003eUna 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.\u003c/p\u003e\n\u003ch2\u003e\n\u003ca href=\"#tratamiento-seg%C3%BAn-las-condiciones-de-fallo-de-verificaci%C3%B3n\" class=\"anchor\" id=\"tratamiento-según-las-condiciones-de-fallo-de-verificación\"\u003e\u003c/a\u003eTratamiento según las condiciones de fallo de verificación\u003c/h2\u003e\n\u003cp\u003eEn 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 \u003ca href=\"https://github.com/x402-foundation/x402/blob/main/typescript/packages/http/express/src/index.ts\"\u003emiddleware oficial de Express\u003c/a\u003e como referencia del comportamiento esperado.\u003c/p\u003e\n\u003cdiv class=\"overflow-x-auto\"\u003e\u003ctable\u003e\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth\u003eCondición de prueba\u003c/th\u003e\n\u003cth\u003eTratamiento esperado\u003c/th\u003e\n\u003cth\u003eComprobación adicional\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd data-label=\"Condición de prueba\"\u003eSin cabecera de pago\u003c/td\u003e\n\u003ctd data-label=\"Tratamiento esperado\"\u003eDevolver 402 y las condiciones de pago\u003c/td\u003e\n\u003ctd data-label=\"Comprobación adicional\"\u003eSin cuerpo de pago\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd data-label=\"Condición de prueba\"\u003eSe propone otro token o destinatario\u003c/td\u003e\n\u003ctd data-label=\"Tratamiento esperado\"\u003eRechazar mediante la política del cliente\u003c/td\u003e\n\u003ctd data-label=\"Comprobación adicional\"\u003eNo generar una firma\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd data-label=\"Condición de prueba\"\u003eFirma incorrecta\u003c/td\u003e\n\u003ctd data-label=\"Tratamiento esperado\"\u003eBloquear por fallo de verificación\u003c/td\u003e\n\u003ctd data-label=\"Comprobación adicional\"\u003eNo ejecutar el manejador de pago\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd data-label=\"Condición de prueba\"\u003eSaldo insuficiente\u003c/td\u003e\n\u003ctd data-label=\"Tratamiento esperado\"\u003eBloquear por fallo de verificación o liquidación\u003c/td\u003e\n\u003ctd data-label=\"Comprobación adicional\"\u003eNo registrar la liquidación como correcta\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd data-label=\"Condición de prueba\"\u003eResultado de liquidación fallido\u003c/td\u003e\n\u003ctd data-label=\"Tratamiento esperado\"\u003eBloquear la respuesta de pago\u003c/td\u003e\n\u003ctd data-label=\"Comprobación adicional\"\u003eNo enviar ni siquiera el cuerpo ya preparado\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd data-label=\"Condición de prueba\"\u003eRetraso en la respuesta del facilitator\u003c/td\u003e\n\u003ctd data-label=\"Tratamiento esperado\"\u003eMantener pendiente al no haberse confirmado el éxito\u003c/td\u003e\n\u003ctd data-label=\"Comprobación adicional\"\u003eProhibir la generación automática de una nueva autorización\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd data-label=\"Condición de prueba\"\u003eError al consultar el recibo por RPC\u003c/td\u003e\n\u003ctd data-label=\"Tratamiento esperado\"\u003eConservar el hash de transacción y volver a consultar\u003c/td\u003e\n\u003ctd data-label=\"Comprobación adicional\"\u003eNo dar por hecho que el pago ha fallado\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\u003c/div\u003e\n\u003cp\u003eEn 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.\u003c/p\u003e\n\u003cp\u003eEl 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.\u003c/p\u003e\n\u003ch2\u003e\n\u003ca href=\"#p%C3%A9rdida-de-respuesta-tras-la-liquidaci%C3%B3n-y-recuperaci%C3%B3n-mediante-reenv%C3%ADo\" class=\"anchor\" id=\"pérdida-de-respuesta-tras-la-liquidación-y-recuperación-mediante-reenvío\"\u003e\u003c/a\u003ePérdida de respuesta tras la liquidación y recuperación mediante reenvío\u003c/h2\u003e\n\u003cp\u003eGuarde 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 \u003ca href=\"https://docs.x402.org/extensions/payment-identifier\"\u003edocumentación de la extensión Payment-Identifier\u003c/a\u003e.\u003c/p\u003e\n\u003cp\u003eLa propiedad que evita procesar una operación por duplicado aunque se solicite de nuevo se denomina idempotencia. \u003ccode\u003epayment-identifier\u003c/code\u003e proporciona un identificador de pago para este fin. Añadir el identificador no basta para que esta función quede implementada automáticamente.\u003c/p\u003e\n\u003ch3\u003e\n\u003ca href=\"#comparaci%C3%B3n-entre-pagos-duplicados-y-reenv%C3%ADos\" class=\"anchor\" id=\"comparación-entre-pagos-duplicados-y-reenvíos\"\u003e\u003c/a\u003eComparación entre pagos duplicados y reenvíos\u003c/h3\u003e\n\u003cp\u003eDebe 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 \u003ca href=\"https://eips.ethereum.org/EIPS/eip-3009\"\u003eespecificación ERC-3009\u003c/a\u003e.\u003c/p\u003e\n\u003cdiv class=\"overflow-x-auto\"\u003e\u003ctable\u003e\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth\u003eSituación\u003c/th\u003e\n\u003cth\u003eDesde la perspectiva de la autorización en la cadena\u003c/th\u003e\n\u003cth\u003eDesde la perspectiva de la operación de la API\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd data-label=\"Situación\"\u003eVolver a liquidar la misma autorización\u003c/td\u003e\n\u003ctd data-label=\"Desde la perspectiva de la autorización en la cadena\"\u003eSujeta a la comprobación de nonce ya utilizado\u003c/td\u003e\n\u003ctd data-label=\"Desde la perspectiva de la operación de la API\"\u003eEs necesario consultar el resultado existente\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd data-label=\"Situación\"\u003eCrear una nueva autorización para el mismo pedido\u003c/td\u003e\n\u003ctd data-label=\"Desde la perspectiva de la autorización en la cadena\"\u003ePuede tratarse como una autorización independiente\u003c/td\u003e\n\u003ctd data-label=\"Desde la perspectiva de la operación de la API\"\u003eEs necesario evitar pagos duplicados\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd data-label=\"Situación\"\u003ePérdida de respuesta tras una liquidación correcta\u003c/td\u003e\n\u003ctd data-label=\"Desde la perspectiva de la autorización en la cadena\"\u003eEl movimiento de activos puede haberse completado\u003c/td\u003e\n\u003ctd data-label=\"Desde la perspectiva de la operación de la API\"\u003eEs necesario volver a entregar el contenido\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd data-label=\"Situación\"\u003eTiempo de espera agotado tras solicitar la liquidación\u003c/td\u003e\n\u003ctd data-label=\"Desde la perspectiva de la autorización en la cadena\"\u003eEl resultado aún es incierto\u003c/td\u003e\n\u003ctd data-label=\"Desde la perspectiva de la operación de la API\"\u003eEs necesario mantener el estado pendiente y comprobar la liquidación\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\u003c/div\u003e\n\u003cp\u003eEl 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.\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003eDeclare en el servidor la compatibilidad con la extensión \u003ccode\u003epayment-identifier\u003c/code\u003e.\u003c/li\u003e\n\u003cli\u003eConserve en el cliente el identificador de la solicitud lógica.\u003c/li\u003e\n\u003cli\u003eVincule en el servidor el identificador con el pagador y el contenido de la solicitud.\u003c/li\u003e\n\u003cli\u003eRegistre de forma atómica el estado de procesamiento para impedir ejecuciones simultáneas.\u003c/li\u003e\n\u003cli\u003eCuando la liquidación se complete correctamente, guarde las pruebas de la transacción y el resultado de la respuesta.\u003c/li\u003e\n\u003cli\u003eSi los permisos y el contenido de la nueva solicitud coinciden, devuelva el resultado guardado.\u003c/li\u003e\n\u003cli\u003eSi el resultado de liquidación es incierto, compruebe primero la autorización existente.\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003eUn 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.\u003c/p\u003e\n\u003cp\u003eGuarde 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 \u003ccode\u003eTransfer\u003c/code\u003e por sí sola no demuestra a qué pedido corresponde.\u003c/p\u003e\n\u003ch2\u003e\n\u003ca href=\"#errores-frecuentes-en-la-implementaci%C3%B3n-de-pagos\" class=\"anchor\" id=\"errores-frecuentes-en-la-implementación-de-pagos\"\u003e\u003c/a\u003eErrores frecuentes en la implementación de pagos\u003c/h2\u003e\n\u003cp\u003eConfundir 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 \u003ca href=\"https://docs.x402.org/guides/migration-v1-to-v2\"\u003eguía de migración de x402\u003c/a\u003e.\u003c/p\u003e\n\u003cdiv class=\"overflow-x-auto\"\u003e\u003ctable\u003e\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth\u003eError frecuente\u003c/th\u003e\n\u003cth\u003eCriterio correcto\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd data-label=\"Error frecuente\"\u003eInterpretar \u003ccode\u003eextra.version: \"2\"\u003c/code\u003e como la versión de x402\u003c/td\u003e\n\u003ctd data-label=\"Criterio correcto\"\u003eComprobar la versión del protocolo mediante \u003ccode\u003ex402Version\u003c/code\u003e\n\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd data-label=\"Error frecuente\"\u003eUsar \u003ccode\u003emaxAmountRequired\u003c/code\u003e en v2\u003c/td\u003e\n\u003ctd data-label=\"Criterio correcto\"\u003eUsar \u003ccode\u003eamount\u003c/code\u003e para el importe de las condiciones de pago\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd data-label=\"Error frecuente\"\u003eCrear por cuenta propia la cabecera \u003ccode\u003eX-PAYMENT-REQUIRED\u003c/code\u003e\n\u003c/td\u003e\n\u003ctd data-label=\"Criterio correcto\"\u003eUsar el cuerpo en v1 y \u003ccode\u003ePAYMENT-REQUIRED\u003c/code\u003e en v2\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd data-label=\"Error frecuente\"\u003eTratar \u003ccode\u003eisValid: true\u003c/code\u003e como confirmación de recepción de fondos\u003c/td\u003e\n\u003ctd data-label=\"Criterio correcto\"\u003eComprobar por separado el resultado de \u003ccode\u003e/settle\u003c/code\u003e\n\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd data-label=\"Error frecuente\"\u003eTratar el campo \u003ccode\u003eto\u003c/code\u003e de nivel superior de la transacción como el destinatario de USDC\u003c/td\u003e\n\u003ctd data-label=\"Criterio correcto\"\u003eComprobar \u003ccode\u003eTransfer.to\u003c/code\u003e de USDC\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd data-label=\"Error frecuente\"\u003eSuponer que el firmante y el remitente de la transacción son el mismo\u003c/td\u003e\n\u003ctd data-label=\"Criterio correcto\"\u003eComparar el pagador de la autorización con \u003ccode\u003eTransfer.from\u003c/code\u003e\n\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd data-label=\"Error frecuente\"\u003eSumar los importes recibidos en la red de prueba a las ventas\u003c/td\u003e\n\u003ctd data-label=\"Criterio correcto\"\u003eSeparar los libros de la red principal y de la red de prueba\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd data-label=\"Error frecuente\"\u003eCrear un nuevo pago cada vez que se agota el tiempo de espera\u003c/td\u003e\n\u003ctd data-label=\"Criterio correcto\"\u003eRecuperar primero el pedido existente y el estado de su autorización\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd data-label=\"Error frecuente\"\u003eEquiparar la versión del paquete SDK con la del protocolo\u003c/td\u003e\n\u003ctd data-label=\"Criterio correcto\"\u003eGestionar por separado la versión del paquete y \u003ccode\u003ex402Version\u003c/code\u003e\n\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\u003c/div\u003e\n\u003cp\u003eLa 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 \u003ca href=\"https://eips.ethereum.org/EIPS/eip-3009\"\u003eespecificación ERC-3009\u003c/a\u003e.\u003c/p\u003e\n\u003ch2\u003e\n\u003ca href=\"#revisi%C3%B3n-de-seguridad-y-alcance-de-la-confianza-en-servicios-externos\" class=\"anchor\" id=\"revisión-de-seguridad-y-alcance-de-la-confianza-en-servicios-externos\"\u003e\u003c/a\u003eRevisión de seguridad y alcance de la confianza en servicios externos\u003c/h2\u003e\n\u003cp\u003eControle 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 \u003ca href=\"https://github.com/x402-foundation/x402/blob/main/docs/core-concepts/facilitator.md\"\u003edocumentación del facilitator\u003c/a\u003e.\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eNo dé acceso al contenido basándose en un mensaje de éxito del cliente.\u003c/li\u003e\n\u003cli\u003eCompare la cadena, el token, el importe y el destinatario declarados por el servidor.\u003c/li\u003e\n\u003cli\u003eNo registre claves privadas ni frases semilla.\u003c/li\u003e\n\u003cli\u003eExcluya también las firmas completas de autorización de los registros de acceso habituales.\u003c/li\u003e\n\u003cli\u003eLimite el tamaño de las cabeceras de pago y el tiempo de procesamiento de las solicitudes.\u003c/li\u003e\n\u003cli\u003eCompruebe que las respuestas de pago no queden en cachés compartidas.\u003c/li\u003e\n\u003cli\u003eSepare las ubicaciones de almacenamiento de las claves de prueba y de producción.\u003c/li\u003e\n\u003cli\u003eNo cree una ruta alternativa sin pago cuando falle el facilitator.\u003c/li\u003e\n\u003cli\u003ePruebe de forma efectiva la caducidad de las autorizaciones y las solicitudes duplicadas.\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eLas dependencias fijadas para esta práctica aún presentan advertencias de seguridad. \u003ccode\u003enpm audit\u003c/code\u003e informó de un aviso relacionado con zod. Consulte los detalles en el \u003ca href=\"https://github.com/advisories/GHSA-mrhx-c7xc-m3w5\"\u003eaviso de seguridad de GitHub\u003c/a\u003e.\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e\u003cspan\u003enpm\u003c/span\u003e\u003cspan\u003e audit\n\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003eAntes 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.\u003c/p\u003e\n\u003ch3\u003e\n\u003ca href=\"#comparaci%C3%B3n-entre-un-servidor-propio-y-cloudflare-gateway\" class=\"anchor\" id=\"comparación-entre-un-servidor-propio-y-cloudflare-gateway\"\u003e\u003c/a\u003eComparación entre un servidor propio y Cloudflare Gateway\u003c/h3\u003e\n\u003cp\u003eAl 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 \u003ca href=\"https://developers.cloudflare.com/monetization-gateway/x402/\"\u003edocumentación de x402 de Cloudflare\u003c/a\u003e.\u003c/p\u003e\n\u003cdiv class=\"overflow-x-auto\"\u003e\u003ctable\u003e\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth\u003eAspecto\u003c/th\u003e\n\u003cth\u003eMétodo con Express de este artículo\u003c/th\u003e\n\u003cth\u003eCloudflare Monetization Gateway\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd data-label=\"Aspecto\"\u003eProcesamiento del pago del cliente\u003c/td\u003e\n\u003ctd data-label=\"Método con Express de este artículo\"\u003eMiddleware de Express\u003c/td\u003e\n\u003ctd data-label=\"Cloudflare Monetization Gateway\"\u003eGateway\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd data-label=\"Aspecto\"\u003ePunto de verificación del servidor de origen\u003c/td\u003e\n\u003ctd data-label=\"Método con Express de este artículo\"\u003eIntegración con el facilitator elegido\u003c/td\u003e\n\u003ctd data-label=\"Cloudflare Monetization Gateway\"\u003eVerificación del JWT \u003ccode\u003ePAYMENT-CONTEXT\u003c/code\u003e\n\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd data-label=\"Aspecto\"\u003eEntrega del resultado de liquidación\u003c/td\u003e\n\u003ctd data-label=\"Método con Express de este artículo\"\u003e\n\u003ccode\u003ePAYMENT-RESPONSE\u003c/code\u003e del middleware\u003c/td\u003e\n\u003ctd data-label=\"Cloudflare Monetization Gateway\"\u003eGateway genera el recibo de liquidación\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd data-label=\"Aspecto\"\u003eComprobaciones adicionales\u003c/td\u003e\n\u003ctd data-label=\"Método con Express de este artículo\"\u003eCadenas admitidas y autenticación del facilitator\u003c/td\u003e\n\u003ctd data-label=\"Cloudflare Monetization Gateway\"\u003eVerificación de la firma JWT y protección del acceso al origen\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\u003c/div\u003e\n\u003cp\u003e\u003ccode\u003ePAYMENT-CONTEXT\u003c/code\u003e 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 \u003ca href=\"https://developers.cloudflare.com/monetization-gateway/configuration/payment-validation/\"\u003edocumentación Payment validation de Cloudflare\u003c/a\u003e.\u003c/p\u003e\n\u003cp\u003eAunque 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.\u003c/p\u003e\n\u003ch2\u003e\n\u003ca href=\"#distinci%C3%B3n-entre-uso-real-y-registros-de-liquidaci%C3%B3n\" class=\"anchor\" id=\"distinción-entre-uso-real-y-registros-de-liquidación\"\u003e\u003c/a\u003eDistinción entre uso real y registros de liquidación\u003c/h2\u003e\n\u003cp\u003eEl 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.\u003c/p\u003e\n\u003cdiv class=\"overflow-x-auto\"\u003e\u003ctable\u003e\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth\u003eRegistro\u003c/th\u003e\n\u003cth\u003ePregunta que permite responder\u003c/th\u003e\n\u003cth\u003eRegistro adicional necesario\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd data-label=\"Registro\"\u003eRespuesta 402\u003c/td\u003e\n\u003ctd data-label=\"Pregunta que permite responder\"\u003eCuántas veces se han solicitado las condiciones de pago\u003c/td\u003e\n\u003ctd data-label=\"Registro adicional necesario\"\u003eSi el pago se ha producido realmente\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd data-label=\"Registro\"\u003eVerificación correcta\u003c/td\u003e\n\u003ctd data-label=\"Pregunta que permite responder\"\u003eSi la autorización era válida\u003c/td\u003e\n\u003ctd data-label=\"Registro adicional necesario\"\u003eResultado de liquidación\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd data-label=\"Registro\"\u003eTransferencia de USDC\u003c/td\u003e\n\u003ctd data-label=\"Pregunta que permite responder\"\u003eSi se han movido los activos\u003c/td\u003e\n\u003ctd data-label=\"Registro adicional necesario\"\u003ePedido al que corresponde\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd data-label=\"Registro\"\u003eLiquidación completada por pedido\u003c/td\u003e\n\u003ctd data-label=\"Pregunta que permite responder\"\u003eSi se ha pagado la solicitud de pago\u003c/td\u003e\n\u003ctd data-label=\"Registro adicional necesario\"\u003eEstado de entrega de la respuesta\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd data-label=\"Registro\"\u003eRegistro de reentrega\u003c/td\u003e\n\u003ctd data-label=\"Pregunta que permite responder\"\u003eSi se ha recuperado una solicitud ya pagada\u003c/td\u003e\n\u003ctd data-label=\"Registro adicional necesario\"\u003eIdentificador que permita distinguirla de un pago nuevo\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\u003c/div\u003e\n\u003cp\u003eDistinga 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.\u003c/p\u003e\n\u003ch2\u003e\n\u003ca href=\"#procedimiento-de-transici%C3%B3n-a-la-red-principal-de-base\" class=\"anchor\" id=\"procedimiento-de-transición-a-la-red-principal-de-base\"\u003e\u003c/a\u003eProcedimiento de transición a la red principal de Base\u003c/h2\u003e\n\u003cp\u003eConsidere 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 \u003ca href=\"https://docs.x402.org/getting-started/quickstart-for-sellers#running-on-mainnet\"\u003eguía oficial para vendedores\u003c/a\u003e.\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003eCompruebe que el facilitator elegido admita la red principal de Base.\u003c/li\u003e\n\u003cli\u003eCompruebe en \u003ccode\u003e/supported\u003c/code\u003e la compatibilidad con v2, \u003ccode\u003eexact\u003c/code\u003e y \u003ccode\u003eeip155:8453\u003c/code\u003e.\u003c/li\u003e\n\u003cli\u003eConfigure la autenticación y las condiciones de uso exigidas por el proveedor.\u003c/li\u003e\n\u003cli\u003eCambie la red tanto en el servidor como en el cliente.\u003c/li\u003e\n\u003cli\u003eCambie la dirección permitida de USDC del cliente por la dirección de la red principal.\u003c/li\u003e\n\u003cli\u003eVuelva a contrastar el importe de la respuesta 402 y la dirección receptora real.\u003c/li\u003e\n\u003cli\u003eIntegre el almacenamiento para solicitudes duplicadas y el procedimiento de recuperación ante fallos.\u003c/li\u003e\n\u003cli\u003eComplete la revisión de seguridad de las dependencias de producción.\u003c/li\u003e\n\u003cli\u003eCompruebe la transferencia real y la entrega del contenido con el importe pequeño configurado.\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003eLa 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 \u003ca href=\"https://docs.x402.org/core-concepts/network-and-token-support\"\u003edocumentación sobre compatibilidad con redes y tokens\u003c/a\u003e.\u003c/p\u003e\n","tags":["Stablecoin","Agentes de IA","Desarrollo de IA","Monetización de contenido","Herramientas de desarrollo"],"faqs":[{"question":"¿En qué se diferencia x402 de la confirmación de un depósito normal de USDC?","answer":"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."},{"question":"¿Cuáles son las cabeceras de pago de x402 v2?","answer":"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."},{"question":"¿Existe la cabecera X-PAYMENT-REQUIRED en v1?","answer":"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."},{"question":"¿El éxito de /verify significa que el pago se ha completado?","answer":"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."},{"question":"¿Se pueden considerar los USDC de prueba de Base Sepolia como ingresos reales?","answer":"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."},{"question":"¿Hay que introducir una clave privada en el servidor receptor?","answer":"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."},{"question":"¿Cuál es el valor de amount para 0.001 USDC?","answer":"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\"."},{"question":"¿Un recibo de transacción satisfactorio confirma también la recepción de USDC?","answer":"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."},{"question":"¿Es seguro reenviar la misma solicitud de pago?","answer":"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."},{"question":"¿Si no hay PAYMENT-RESPONSE, basta con volver a pagar?","answer":"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."},{"question":"¿Con x402 hay que usar únicamente el facilitador de una empresa específica?","answer":"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."},{"question":"¿También se limita automáticamente el gasto de los agentes de IA?","answer":"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."},{"question":"¿PAYMENT-CONTEXT de Cloudflare es una cabecera estándar de firma de pago?","answer":"PAYMENT-CONTEXT es un JWT que Gateway envía al servidor de origen. Su finalidad es distinta de la de PAYMENT-SIGNATURE del cliente."},{"question":"¿Se puede desplegar el ejemplo directamente en la red principal?","answer":"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":[{"url":"https://github.com/x402-foundation/x402/blob/main/specs/x402-specification-v2.md","title":"Especificación del protocolo x402 v2","type":"source"},{"url":"https://github.com/x402-foundation/x402/blob/main/specs/transports-v1/http.md","title":"Transporte HTTP de x402 v1","type":"source"},{"url":"https://github.com/x402-foundation/x402/blob/main/specs/transports-v2/http.md","title":"Transporte HTTP de x402 v2","type":"source"},{"url":"https://docs.x402.org/guides/migration-v1-to-v2","title":"Guía de migración de x402: de V1 a V2","type":"source"},{"url":"https://github.com/x402-foundation/x402/blob/main/docs/core-concepts/facilitator.md","title":"Funciones y responsabilidades del facilitador de x402","type":"source"},{"url":"https://docs.x402.org/getting-started/quickstart-for-sellers","title":"Guía de inicio rápido de x402 para vendedores","type":"source"},{"url":"https://docs.x402.org/getting-started/quickstart-for-buyers","title":"Guía de inicio rápido de x402 para compradores","type":"source"},{"url":"https://github.com/x402-foundation/x402/tree/main/examples/typescript/clients/fetch","title":"Ejemplo del cliente fetch oficial de x402 en TypeScript","type":"source"},{"url":"https://github.com/x402-foundation/x402/blob/main/typescript/packages/http/express/src/index.ts","title":"Implementación del middleware de Express para x402","type":"source"},{"url":"https://github.com/x402-foundation/x402/blob/main/typescript/packages/core/src/client/x402Client.ts","title":"Selección de condiciones de pago e implementación de políticas en x402Client","type":"source"},{"url":"https://github.com/x402-foundation/x402/blob/main/typescript/packages/mechanisms/evm/src/exact/server/scheme.ts","title":"Implementación de la conversión de precios en el servidor de ExactEvmScheme de x402","type":"source"},{"url":"https://developers.circle.com/stablecoins/usdc-contract-addresses","title":"Dirección del contrato de USDC de Circle","type":"data_point"},{"url":"https://docs.base.org/get-started/connect-to-base","title":"Información sobre la red principal de Base y la red Base Sepolia","type":"data_point"},{"url":"https://faucet.circle.com/","title":"Circle Testnet Faucet","type":"source"},{"url":"https://viem.sh/docs/actions/public/getTransactionReceipt","title":"viem getTransactionReceipt","type":"source"},{"url":"https://viem.sh/docs/contract/parseEventLogs","title":"viem parseEventLogs","type":"source"},{"url":"https://eips.ethereum.org/EIPS/eip-20","title":"Estándar de tokens ERC-20","type":"source"},{"url":"https://eips.ethereum.org/EIPS/eip-3009","title":"ERC-3009 Transferencia con autorización","type":"source"},{"url":"https://docs.x402.org/extensions/payment-identifier","title":"Extensión de idempotencia Payment-Identifier de x402","type":"source"},{"url":"https://developers.cloudflare.com/monetization-gateway/x402/","title":"Protocolo x402 de Cloudflare Monetization Gateway","type":"source"},{"url":"https://developers.cloudflare.com/monetization-gateway/configuration/payment-validation/","title":"Validación de pagos de Cloudflare Monetization Gateway","type":"source"},{"url":"https://docs.x402.org/core-concepts/network-and-token-support","title":"Redes y tokens compatibles con x402","type":"source"},{"url":"https://github.com/advisories/GHSA-mrhx-c7xc-m3w5","title":"Aviso de seguridad de GitHub: agotamiento de memoria por la validación de colecciones de gran tamaño en Zod","type":"source"}],"images":[{"id":2199,"url":"https://injoys.com/rails/active_storage/blobs/proxy/eyJfcmFpbHMiOnsiZGF0YSI6MzM4MDcsInB1ciI6ImJsb2JfaWQifX0=--49c502fd8da16158a617c3586dfa81ced4bc95df/ai-f0ae2b5c.webp","is_representative":true,"generation_method":"ai_photo","license":"ai_generated","mime_type":"image/webp","width":1536,"height":1024,"translations":{"ko":{"alt":"짙은 회색 스웨터를 입은 남성이 서버 랙 선반에 놓인 태블릿 화면을 살펴보고 있다.","caption":"메인넷으로 전환하기 전에 테스트 환경에서 x402 결제 연동을 검증하세요.","description":null},"en":{"alt":"A man in a dark gray sweater examines a tablet resting on a server rack shelf.","caption":"Validate the x402 payment integration in a test environment before switching to mainnet.","description":null},"ja":{"alt":"濃いグレーのセーターを着た男性が、サーバーラックの棚に置かれたタブレットを確認している。","caption":"メインネットへ移行する前に、テスト環境でx402の決済連携を検証しましょう。","description":null},"es":{"alt":"Un hombre con un suéter gris oscuro revisa una tableta sobre la bandeja de un rack de servidores.","caption":"Valida la integración de pagos x402 en un entorno de prueba antes de pasar a la red principal.","description":null},"id":{"alt":"Seorang pria bersweater abu-abu gelap memeriksa tablet di atas ambalan rak server.","caption":"Validasi integrasi pembayaran x402 di lingkungan uji sebelum beralih ke mainnet.","description":null},"pt":{"alt":"Um homem de suéter cinza-escuro examina um tablet apoiado na prateleira de um rack de servidores.","caption":"Valide a integração de pagamentos x402 em um ambiente de teste antes de migrar para a rede principal.","description":null},"zh-hant":{"alt":"一名穿著深灰色毛衣的男子正在查看伺服器機架層板上的平板電腦。","caption":"切換至主網前，先在測試環境中驗證 x402 支付整合。","description":null},"de":{"alt":"Ein Mann im dunkelgrauen Pullover prüft ein Tablet auf der Ablage eines Serverracks.","caption":"Prüfen Sie die x402-Zahlungsintegration in einer Testumgebung, bevor Sie ins Mainnet wechseln.","description":null}}},{"id":2200,"url":"https://injoys.com/rails/active_storage/blobs/proxy/eyJfcmFpbHMiOnsiZGF0YSI6MzM4MTMsInB1ciI6ImJsb2JfaWQifX0=--4e70727f132519277c68d1c6279d95585a936549/ai-3dbd1c62.webp","is_representative":false,"generation_method":"ai_semi","license":"ai_generated","mime_type":"image/webp","width":1536,"height":1024,"translations":{"ko":{"alt":"창가에서 여성이 평평하게 펼친 노트북으로 입력하고 있으며, 화면에는 목록과 두 경로가 합쳐지는 흐름도가 보인다.","caption":"중복 요청 복구를 시험해 결제 재시도가 이중 정산으로 이어지지 않는지 확인하세요.","description":null},"en":{"alt":"A woman types on a laptop opened flat, with a list and two paths converging on one endpoint on its screen.","caption":"Test duplicate-request recovery to ensure payment retries do not cause a second settlement.","description":null},"ja":{"alt":"窓辺で女性が平らに開いたノートパソコンを操作し、画面には一覧と2本の経路が合流するフロー図が表示されている。","caption":"重複リクエストの復旧をテストし、決済の再試行で二重精算が起きないことを確認しましょう。","description":null},"es":{"alt":"Una mujer teclea en un portátil abierto en plano; la pantalla muestra una lista y dos rutas que convergen.","caption":"Prueba la recuperación de solicitudes duplicadas para evitar una segunda liquidación al reintentar el pago.","description":null},"id":{"alt":"Seorang perempuan mengetik di laptop yang dibuka rata, dengan daftar dan diagram dua jalur yang menyatu di layar.","caption":"Uji pemulihan permintaan duplikat untuk memastikan percobaan ulang pembayaran tidak memicu penyelesaian ganda.","description":null},"pt":{"alt":"Uma mulher digita num notebook aberto na horizontal, com uma lista e duas rotas convergentes na tela.","caption":"Teste a recuperação de solicitações duplicadas para garantir que novas tentativas de pagamento não gerem liquidação dupla.","description":null},"zh-hant":{"alt":"一名女子在窗邊操作完全攤平的筆記型電腦，螢幕顯示清單及兩條路徑匯合的流程圖。","caption":"測試重複請求的復原流程，確認付款重試不會造成重複結算。","description":null},"de":{"alt":"Eine Frau tippt auf einem flach aufgeklappten Laptop; das Display zeigt eine Liste und zwei zusammenlaufende Pfade.","caption":"Testen Sie die Wiederherstellung bei doppelten Anfragen, damit Zahlungswiederholungen keine zweite Abrechnung auslösen.","description":null}}}],"published_at":"2026-10-28T19:20:55+09:00","updated_at":"2026-10-28T19:20:55+09:00","license":"cc_by","translation_status":"reviewed","available_locales":["ko","en","ja","es"],"data_locales":["ko","en","ja","es","id","pt","zh-hant","de"],"url":"https://injoys.com/es/articles/x402-payments-2026-v2-base-usdc-settlement-guide"}