La Payment Request API en 2026: cómo funcionan los pagos en el navegador (parte 1)

La Payment Request API en 2026: cómo funcionan los pagos en el navegador (parte 1)

Actualizado en noviembre de 2026. La primera versión de este artículo, de junio de 2023, usaba el método de pago basic-card y un formato antiguo de Google Pay. Hoy no funciona ninguno de los dos, así que el código se ha reescrito.

La Payment Request API permite que una página abra la ventana de pago del navegador en lugar de mostrar su propio formulario de tarjeta. En Chrome esa ventana es Google Pay; en Safari, Apple Pay. El usuario elige una tarjeta que ya tiene guardada, confirma y la página recibe un token que puede enviar a su proveedor de pagos. En esta serie de dos partes vemos cómo funciona la API hoy, dónde se puede usar y qué sigue tocando programar a mano.

Lo que hace la API y lo que no hace

La API hace tres cosas:

  • muestra una ventana de pago que dibuja el propio navegador, así que es igual en todas las webs;
  • recoge los datos de pago y, si se los pides, el nombre, el email, el teléfono y la dirección de envío del comprador;
  • le devuelve todo eso a tu página en un objeto PaymentResponse.

Lo que no hace es cobrar. El token de la respuesta tiene que llegar a tu servidor, y es tu servidor el que hace el cobro a través de tu proveedor de pagos (Stripe, Adyen, Braintree, la pasarela de tu banco…). La API solo sustituye al formulario de pago.

Dónde funciona en 2026

NavegadorPayment Request APIMétodos de pago
Chrome (escritorio y Android)Sí, desde Chrome 60 (53 en Android)Google Pay y otras apps de pago de terceros
EdgeSíSegún las apps de pago disponibles
Safari (macOS e iOS)Sí, desde Safari 11.1Solo Apple Pay
FirefoxNo, solo con el flag dom.payments.request.enabled—

La propia documentación de Google lo dice claramente: hoy Chrome es el único navegador que admite la Payment Request API con métodos de pago de terceros, Google Pay incluido. Si necesitas Google Pay en otros navegadores, lo que toca es la librería de JavaScript de Google Pay; la Payment Request API es el camino nativo del navegador.

Hay dos requisitos que valen para todos:

  • HTTPS: la API solo existe en contextos seguros (localhost cuenta como seguro, algo muy práctico para hacer pruebas);
  • una acción del usuario: show() solo funciona como respuesta a un clic o a una tecla. Si lo llamas al cargar la página, falla con un SecurityError.

Qué pasó con basic-card

La versión de 2023 de este tutorial usaba basic-card, un método con el que el propio navegador recogía el número de la tarjeta. El W3C Web Payments Working Group abandonó esa especificación en agosto de 2021 y los navegadores ya no lo ofrecen. Ahora las tarjetas llegan a la ventana de pago a través de un monedero como Google Pay o Apple Pay. Si copias un ejemplo antiguo que solo incluye basic-card, show() se rechaza con un NotSupportedError.

Un ejemplo mínimo con Google Pay en modo de prueba

A la página le bastan dos elementos: un botón con el id pay-button, oculto al principio con el atributo hidden para que solo aparezca si el navegador puede pagar, y un párrafo vacío con el id result para los mensajes. La página completa, con el HTML, está en la demo de CodePen, donde también puedes probarla.

El JavaScript:

const button = document.getElementById('pay-button');
const result = document.getElementById('result');

// Google Pay, en el formato que documenta Google para la Payment Request API (versión 2 de la API).
// environment: 'TEST' devuelve tarjetas ficticias: no se cobra nada.
const googlePay = {
  supportedMethods: 'https://google.com/pay',
  data: {
    environment: 'TEST',
    apiVersion: 2,
    apiVersionMinor: 0,
    merchantInfo: {
      merchantName: 'Example Merchant'
      // merchantId: '12345678901234567890'  (te lo da Google para producción)
    },
    allowedPaymentMethods: [{
      type: 'CARD',
      parameters: {
        allowedAuthMethods: ['PAN_ONLY', 'CRYPTOGRAM_3DS'],
        allowedCardNetworks: ['MASTERCARD', 'VISA']
      },
      tokenizationSpecification: {
        type: 'PAYMENT_GATEWAY',
        parameters: {
          gateway: 'example',
          gatewayMerchantId: 'exampleGatewayMerchantId'
        }
      }
    }]
  }
};

const details = {
  total: { label: 'Total', amount: { currency: 'EUR', value: '100.00' } },
  displayItems: [
    { label: 'Producto A', amount: { currency: 'EUR', value: '50.00' } },
    { label: 'Producto B', amount: { currency: 'EUR', value: '50.00' } }
  ]
};

// 1. Mostrar el botón solo si el navegador tiene la API y puede usar el método
async function setUp() {
  if (!window.PaymentRequest) {
    return; // se queda el proceso de pago normal
  }
  const request = new PaymentRequest([googlePay], details);
  if (await request.canMakePayment()) {
    button.hidden = false;
  }
}

// 2. Al hacer clic, abrir la ventana de pago
button.addEventListener('click', async () => {
  const request = new PaymentRequest([googlePay], details);
  try {
    const response = await request.show();
    const charged = await sendToServer(response);
    await response.complete(charged ? 'success' : 'fail');
    result.textContent = charged ? 'Gracias por tu compra.' : 'No se ha podido completar el pago.';
  } catch (error) {
    if (error.name === 'AbortError') {
      result.textContent = 'Pago cancelado.';
    } else if (error.name === 'NotSupportedError') {
      result.textContent = 'Este navegador no tiene ningún método de pago de los que aceptamos.';
    } else {
      console.error(error);
      result.textContent = 'Algo ha fallado.';
    }
  }
});

// 3. Solo para la demo: en una tienda real esto envía response.details por POST a tu servidor,
//    que cobra el token a través de tu proveedor de pagos
async function sendToServer(response) {
  console.log(response.methodName, response.details);
  return true;
}

setUp();

El ejemplo, paso a paso

Los métodos de pago

El primer argumento de new PaymentRequest() es un array de métodos de pago. Cada uno lleva una cadena supportedMethods, un identificador como 'https://google.com/pay' o 'https://apple.com/apple-pay', y un objeto data cuyo formato decide quien gestiona ese método. En Google Pay, data es el mismo objeto de petición que en la Pay API de Google: apiVersion: 2, un bloque merchantInfo y un array allowedPaymentMethods de objetos. El tokenizationSpecification indica qué proveedor de pagos recibirá el token; los valores exactos de gateway y gatewayMerchantId te los da tu proveedor.

Los tutoriales antiguos, incluida la primera versión de este, escribían supportedMethods como un array y allowedPaymentMethods como ['TOKENIZED_CARD', 'CARD']. Ese era el formato de la primera versión de la API de Google Pay; la actual espera los objetos que ves arriba.

Los detalles del pago

El segundo argumento describe lo que el usuario va a pagar: el total, que es obligatorio, y, si quieres, una lista de displayItems que la ventana muestra como desglose. Los importes son cadenas ('100.00'), no números, y la moneda es un código ISO 4217. Con Google Pay el total va aquí y no hace falta el campo transactionInfo que Google Pay usa fuera de esta API.

Comprobar antes de mostrar el botón

canMakePayment() te dice si el navegador puede usar al menos uno de los métodos que has indicado. No necesita un clic, así que el ejemplo lo llama al cargar la página y, si la respuesta es no, el botón se queda oculto. A los usuarios de Firefox, por ejemplo, nunca les aparece un botón que solo iba a fallar.

Mostrar la ventana y terminar

Dentro del manejador del clic, el ejemplo crea una petición nueva y llama a show(). La promesa se resuelve con un PaymentResponse cuando el usuario confirma. El orden de los dos pasos siguientes es importante:

  1. enviar la respuesta a tu servidor y esperar a saber si el cobro ha ido bien o ha fallado;
  2. solo entonces llamar a response.complete('success') o a response.complete('fail'), que cierra la ventana.

La versión de 2023 llamaba primero a complete('success') y procesaba el pago después, es decir, le decía al usuario que todo había ido bien antes incluso de intentar el cobro.

Cancelaciones y errores

Cuando el usuario cierra la ventana, show() no se resuelve con un valor vacío: se rechaza con un AbortError. Por eso el ejemplo trata la cancelación en el bloque catch y mira error.name. NotSupportedError significa que no hay disponible ninguno de tus métodos, y SecurityError suele significar que se ha llamado a show() sin un clic.

Qué llega en la respuesta

response.methodName te dice qué método ha elegido el usuario, por ejemplo 'https://google.com/pay'. response.details contiene los datos de ese método. Con Google Pay es un objeto de datos de pago en el que paymentMethodData.tokenizationData.token es lo que necesita tu proveedor para cobrar la tarjeta. Si has pedido los datos de contacto, llegan en payerName, payerEmail y payerPhone; lo vemos en la parte 2.

Apple Pay

En Safari el método es 'https://apple.com/apple-pay', pero no basta con un bloque de datos: hacen falta una cuenta de comerciante de Apple Pay, un dominio verificado y un paso de validación del comerciante que tu servidor hace con Apple cada vez que se abre la ventana. En la parte 2 vemos cómo encaja ese paso en el mismo código.

¿Conviene usar la API directamente?

Para aprender cómo funcionan los pagos en el navegador, sí: todo el proceso cabe en una página de código. En una tienda en producción, la mayoría de los equipos usa el botón o el componente de pago de su proveedor, que se encarga de los formatos de cada monedero, de la validación del comerciante y de los navegadores que no tienen la API. Aun así, saber lo que pasa por debajo ayuda mucho cuando algo falla.

En la parte 2 pedimos al comprador su nombre, su email y la dirección de envío, actualizamos el precio cuando cambia la dirección y añadimos Apple Pay.

Para saber más