Integraciones

Botón de pago cripto para sitios web

Cómo añadir un botón «Pagar con cripto» a un sitio web: por qué el botón no puede llamar directamente a la API de pagos, el patrón de tres pasos, código funcional de front-end y servidor, y qué proteger.

Un botón «Pagar con cripto» es fácil de añadir, pero no puede ser un fragmento para copiar y pegar: crear un pago requiere tu clave API secreta, que nunca debe llegar al navegador. El botón tiene por tanto que hablar con tu propio servidor, que crea el pago y devuelve la dirección de la página de pago. Esta guía muestra ese patrón con código funcional y los puntos que lo mantienen seguro.

Por qué aún no hay un botón para copiar y pegar

Muchos proveedores de pago ofrecen un botón o un widget incrustable. Qvard todavía no tiene botón sin código: los enlaces de pago están en desarrollo. El checkout incrustado ya está listo para tu sitio. Los SDK están listos. Hoy la integración es por la API, y la API se autentica con una clave secreta en la cabecera Authorization: Bearer.

Esa clave puede crear pagos de tu proyecto, así que debe quedarse en tu servidor. Un botón que llevara la clave en código de front-end se la entregaría a cada visitante. No es una limitación que haya que sortear; es la razón por la que el patrón de abajo tiene un paso en el servidor.

El patrón: botón, tu endpoint, página de pago

Tres pasos forman un botón que funciona:

  1. El botón envía una solicitud a un endpoint de tu servidor, indicando qué quiere comprar el visitante (un producto, un plan), no cuánto cuesta.
  2. Tu endpoint busca el precio, crea tu propio registro de pedido y llama a Qvard: un POST a https://api.qvard.com/api/v1/payment con la clave en la cabecera Authorization: Bearer y un JSON con tu número de pedido como id y el importe como price en dólares estadounidenses. La respuesta es 201 con un redirectUrl.
  3. El navegador se redirige a ese redirectUrl, la página de pago alojada de Qvard, donde el visitante elige un activo y una red y paga desde una billetera.

Nada secreto toca nunca la página, y la propia página de pago la aloja Qvard, así que no construyes una caja cripto.

El front-end: un botón y una redirección

El botón necesita unas quince líneas. Se desactiva mientras dura la solicitud, envía el identificador del producto y, si todo va bien, envía el navegador a la dirección devuelta. Si falla, vuelve a activarse y muestra un mensaje, para que el visitante pueda reintentarlo.

Ten presente una regla: el navegador envía qué se compra, nunca cuánto. Si el importe saliera de la página, cualquiera podría abrir las herramientas de desarrollo y convertir un plan de 49 dólares en un pago de un dólar.

HTML + JSpay-button.html
<button id="pay-crypto" data-product="pro-plan">Pay with crypto</button>

<script>
  document.getElementById('pay-crypto').addEventListener('click', async (event) => {
    const button = event.currentTarget;
    button.disabled = true;
    try {
      // Send only WHAT is being bought; the server decides the price.
      const res = await fetch('/api/crypto-checkout', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ product: button.dataset.product })
      });
      if (!res.ok) throw new Error('checkout failed');
      const { redirectUrl } = await res.json();
      window.location.assign(redirectUrl);   // the Qvard hosted payment page
    } catch (e) {
      button.disabled = false;
      alert('Could not start the payment. Please try again.');
    }
  });
</script>

El servidor: precio, pedido, pago

El endpoint del ejemplo hace cuatro cosas:

  • Busca el precio en una tabla del servidor y rechaza los productos desconocidos.
  • Crea tu propio pedido y usa su número como id del pago. Así lo encuentra después el webhook.
  • Llama a Qvard y devuelve al navegador solo el redirectUrl. Una respuesta 400 («Error validation», con un mensaje por campo) indica que el cuerpo era incorrecto; un 401 indica que la clave es incorrecta. Ninguno debe reintentarse sin cambios.
  • Es seguro repetirlo. Enviar el mismo id para el mismo método de pago devuelve el pago existente, así que un visitante que pulsa dos veces no crea dos.

Añade limitación de frecuencia al endpoint para que nadie pueda crear miles de pedidos sin pagar, y exige un usuario con sesión o un captcha si tu producto lo necesita.

Node.jscrypto-checkout.js
import express from 'express';
import crypto from 'node:crypto';

const app = express();
const PRICES_USD = { 'pro-plan': 49 };          // prices live on the server, never in the browser

app.post('/api/crypto-checkout', express.json(), async (req, res) => {
  const price = PRICES_USD[req.body.product];
  if (!price) return res.sendStatus(400);

  const orderId = await db.orders.create({ product: req.body.product, amountUsd: price }); // your own order number

  const response = await fetch('https://api.qvard.com/api/v1/payment', {
    method: 'POST',
    headers: { Authorization: 'Bearer ' + process.env.QVARD_API_KEY, 'Content-Type': 'application/json' },
    body: JSON.stringify({ id: String(orderId), price })
  });
  if (response.status !== 201) return res.sendStatus(502);

  const { redirectUrl } = await response.json();
  res.json({ redirectUrl });
});

Tras el clic: decide el webhook

Redirigir al visitante a la página de pago inicia el pago; no lo termina. Cuando el pago se completa, Qvard llama a la callback URL guardada en tu proyecto con tu id y el estado completed. Solo entonces concede el acceso o marca el pedido como pagado. El endpoint debe responder exactamente HTTP 200 y ser seguro si se ejecuta dos veces; consulta cómo proteger los webhooks de pagos cripto.

Todavía no hay URL de retorno tras el pago, así que el visitante vuelve a tu sitio por su cuenta. Dale una página que muestre el estado real del pedido y se actualice mientras espera, no una página de agradecimiento que da el éxito por hecho.

Precios fijos, importes variables y qué sigue

  • Los precios fijos (planes, productos) son el caso fácil: la tabla del servidor los guarda.
  • Los importes variables (donaciones, recargas) necesitan validación en el servidor: un mínimo, un máximo y una comprobación numérica. Un importe inferior al mínimo del método de pago elegido se rechaza con un 400.
  • Varios botones comparten el mismo endpoint; solo cambia el identificador del producto.

El recorrido completo está en cómo aceptar pagos cripto en un sitio web, y la API en API de pagos cripto para desarrolladores. Una factura de demostración muestra la página a la que lleva el botón; las condiciones comerciales están en la página de precios.

FAQ

¿Puedo poner la clave API de Qvard en el código del botón?

No. La clave puede crear pagos de tu proyecto y debe quedarse en tu servidor. El botón debe llamar a tu propio endpoint, que llama a Qvard.

¿Hay un widget incrustable o un botón sin código?

Sí, el checkout incrustado ya es un widget listo para tu sitio. Botón sin código todavía no hay: los enlaces de pago están en desarrollo. Los SDK están listos. Hoy la integración usa la API con un pequeño endpoint de servidor.

¿De dónde debe venir el precio?

De tu servidor, nunca del navegador. El botón envía solo lo que se compra, y el servidor decide el precio en dólares estadounidenses.

¿Cómo sé que el cliente pagó?

Por el webhook que Qvard envía cuando el pago se completa. Que el visitante vuelva a tu sitio no es prueba de pago.

Artículos relacionados

Artículos relacionados