Ir al contenido

Integraciones

En esta página

JavaScript Low-Code SDK

Añade un botón de pago configurable a cualquier página, elige el origen del importe y el tema, y abre la página de pago de Paymos sin montar un formulario.

El Low-Code SDK te permite incrustar un botón de pago directamente en tu web. Cuando un cliente lo pulsa, el SDK resuelve el importe, crea una factura con tu clave pública de SDK (pk_...) y abre el formulario de pago, ya sea como ventana modal en iframe o como redirección a página completa.

El Low-Code SDK es una envoltura cómoda sobre esa misma página de pago que POST /v1/invoices devuelve como payment_url; en modo iframe la abre con ?embed=true. Consulta Página de pago para el contrato de redirección pura y de iframe manual.

Por dentro, el SDK envía peticiones a https://paymos.io/public/v1/sdk —el mismo origen que sirve paymos-widget.js— con tu clave en la cabecera X-Sdk-Key.

Si no hay ningún importe disponible y pasaste una pos_url, el botón abre esa página del Terminal: un teclado numérico donde el importe se introduce a mano. Sin pos_url, una pulsación sin importe resoluble lanza una excepción y emite paymos:error.

Cómo funciona

  • 01Añade el script del SDK y un punto de montaje a tu página
  • 02Llama a PaymosWidget.mount() con tu api_key, tu project_id y las opciones
  • 03El cliente pulsa el botón
  • 04El SDK resuelve el importe (valor fijo, callback o selector de un input)
  • 05Si hay importe, el SDK crea una factura y abre la página de pago
  • 06Si no hay importe y pos_url está configurada, el SDK abre el teclado numérico del Terminal en esa URL
  • 07Si no hay importe ni pos_url, el SDK lanza una excepción y emite paymos:error
  • 08El pago se procesa y se envía un webhook a la URL de webhook que tengas registrada

Instalación

<script src="https://paymos.io/v1/paymos-widget.js"></script>
<div id="paymos-widget"></div>

Resolución del importe

El SDK resuelve el importe del pago en el momento de la pulsación, usando el primer origen disponible:

  • 01amount — una cadena decimal fija pasada en la configuración. Ideal para páginas de producto único o artículos de precio fijo.
  • 02get_amount() — una función callback que devuelve el importe como cadena decimal. Úsala cuando el total se calcule sobre la marcha (por ejemplo, a partir de un carrito).
  • 03amount_selector — un selector CSS que apunta a un elemento <input>. El SDK lee su .value al pulsar. Útil cuando es el propio cliente quien teclea el importe.

Si ninguno de los anteriores devuelve una cadena decimal positiva y válida, el SDK abre el Terminal en tu pos_url: un teclado numérico donde el importe se introduce a mano. Si no configuraste pos_url, la pulsación lanza PaymosWidget requires an amount, amountSelector, or price_id. y no se abre ninguna página de pago.

// Fixed price (price_id) — RECOMMENDED for fixed products.
// Create the price once in the dashboard; the server resolves the amount and
// currency from it, so a buyer cannot change them in DevTools. No amount in the embed.
PaymosWidget.mount('#paymos-widget', {
  api_key: 'YOUR_PUBLIC_KEY',
  price_id: 'price_YOUR_PRICE_ID'
});

// Fixed amount — client-supplied (editable in the browser; use for donations / free-amount)
PaymosWidget.mount('#paymos-widget', {
  api_key: 'YOUR_PUBLIC_KEY',
  project_id: 'prj_YOUR_PROJECT_ID',
  amount: '25.00',
  currency: 'USD'
});

// Dynamic amount — computed at click time
PaymosWidget.mount('#paymos-widget', {
  api_key: 'YOUR_PUBLIC_KEY',
  project_id: 'prj_YOUR_PROJECT_ID',
  get_amount: () => calculateCartTotal().toFixed(2),
  currency: 'USD'
});

// Input selector — reads value from an <input> element
PaymosWidget.mount('#paymos-widget', {
  api_key: 'YOUR_PUBLIC_KEY',
  project_id: 'prj_YOUR_PROJECT_ID',
  amount_selector: '#donation-amount',
  currency: 'USD'
});

Dos formas de integrar

El SDK expone dos puntos de entrada. Elige el que encaje con tu página:

mount(selector, opts) — el SDK dibuja el botón

El SDK inyecta en el elemento de destino un botón de pago con estilo completo y listo para usar (su texto sale de la opción label, con valor por defecto "Support with crypto"). Ideal para páginas de producto único, landings sencillas o widgets de donación: cualquier caso en el que no quieras escribir CSS.

<script src="https://paymos.io/v1/paymos-widget.js"></script>
<div id="paymos-widget"></div>
<script>
  PaymosWidget.mount('#paymos-widget', {
    api_key: 'pk_live_…',
    project_id: 'prj_…',
    amount: '25.00',
    currency: 'USD',
    label: 'Support with crypto'
  });
</script>

open(opts) — tú dibujas el botón y el SDK abre la capa

Conservas el control total del DOM del botón (tu sistema de diseño, tu CSS, tus iconos) y llamas a PaymosWidget.open(opts) desde un manejador de clic. Ideal para páginas de precios con varios planes, carritos y frameworks de interfaz propios (componentes de React, Vue o Svelte).

<button id="buy-growth">Subscribe to Growth — $79/mo</button>
<script>
  document.getElementById('buy-growth').addEventListener('click', function () {
    PaymosWidget.open({
      api_key: 'pk_live_…',
      project_id: 'prj_…',
      amount: 79,
      currency: 'USD',
      client_id: 'plan:growth'
    });
  });
</script>

Ambas formas hablan con el mismo backend, disparan los mismos webhooks y emiten los mismos eventos de ventana. La diferencia está solo en quién se encarga del estilo del botón: open() es lo que lanza el enlace Open Demo del panel (una página de precios con tres botones de estilo independiente, todos enrutados por una misma capa compartida).

Cuándo usar el SDK y cuándo la API REST

El Low-Code SDK es una herramienta del navegador: coloca un botón de pago en una página HTML estática sin backend. Eso lo hace perfecto para:

  • Donaciones y botes de propinas (el importe lo elige el cliente)
  • Flujos de caja en los que el personal teclea el importe
  • Widgets de importe libre («paga lo que quieras»)
  • Demos internas de Sandbox o preproducción

Para cualquier caso en el que el precio esté fijado de tu lado (suscripciones, bienes digitales, pedidos físicos, cursos, licencias), recuerda que el importe vive en la página y se puede editar desde las herramientas de desarrollo: un cliente decidido puede enviar 0.01 por tu plan de 99 $. Usa en su lugar la API REST desde tu servidor, con la clave secreta. El SDK no está roto; este reparto es el mismo en cualquier página de pago del lado del cliente (Stripe, LemonSqueezy, PayPal): la clave publicable en la página, la secreta en el servidor.

Configuración

Parámetro Tipo Obligatorio Descripción
api_key string Clave pública de SDK del panel (pk_...)
project_id string Sí, salvo que se indique price_id Identificador de proyecto (prj_...)
price_id string No Precio fijo creado en el panel (price_...). El servidor resuelve importe y moneda a partir de él, así que el comprador no puede editarlos; recomendado para productos de precio fijo. Tiene prioridad sobre cualquier origen de importe de más abajo
amount string | number No Importe fijo del pago, como cadena decimal o número
get_amount function No Callback que devuelve el importe como cadena decimal en el momento de la pulsación
amount_selector string No Selector CSS de un input con el importe
currency string No Código de moneda fiat (USD, EUR, etc.). Por defecto: USD
client_id string No Tu identificador interno de cliente (se adjunta a la factura)
mode string No "iframe" (por defecto) — capa modal. "redirect" — navegación de página completa
label string No Texto del botón. Por defecto: "Support with crypto"
width string No "auto" (por defecto) o "full" para ocupar el 100 % del ancho
accent_color string No Color de acento del botón (hex). Por defecto: #ff6b35
text_color string No Color del texto del botón (hex). Por defecto: #ffffff. La comprobación de contraste solo corre si además pasas un accent_color propio: si tu color alcanza 4,5
frente a él, el SDK lo respeta; si no, elige negro o blanco según el contraste medido. Con el acento de fábrica no hay comprobación y tu valor queda tal cual
radius number No Radio de las esquinas del botón, 0–32 px. Por defecto: 18
frame_title string No Título accesible del elemento iframe. Por defecto: "Paymos checkout"
aria_label string No Nombre accesible del diálogo modal. Por defecto: "Paymos checkout"
pos_url string No URL de tu página de Terminal o punto de venta. Si está definida, el botón abre el Terminal cuando no se resuelve ningún importe
target string No "_self" (por defecto) o "_blank" (solo en modo redirección)
auto_close_delay number No Milisegundos que la pantalla de éxito permanece visible antes de que la ventana modal se cierre sola. Por defecto: 0 (desactivado). Cualquier interacción dentro de la modal lo cancela.
haptics boolean No Activa una vibración breve en las plataformas que la admiten (Android, algunas PWA). Safari en iOS ignora la Vibration API: allí no hace nada. Respeta prefers-reduced-motion. Por defecto: true
timeout number No Milisegundos antes de abortar la petición de creación de la factura. El valor debe ser positivo; cualquier otro recae en el valor por defecto. Por defecto: 30000
debug boolean No Registra en la consola los objetos Error completos en lugar de solo el mensaje. Por defecto: false

Ejemplo completo

<script src="https://paymos.io/v1/paymos-widget.js"></script>

<div id="paymos-widget"></div>

<script>
  PaymosWidget.mount('#paymos-widget', {
    api_key: 'YOUR_PUBLIC_KEY',
    project_id: 'prj_YOUR_PROJECT_ID',
    amount: '25.00',
    currency: 'USD',
    label: 'Support with crypto',
    mode: 'iframe',
    accent_color: '#FF6B35',
    text_color: '#FFFFFF',
    radius: 20
  });
</script>

API programática

También puedes abrir la página de pago sin montar ningún botón:

// Open checkout programmatically (no button)
await PaymosWidget.open({
  api_key: 'YOUR_PUBLIC_KEY',
  project_id: 'prj_YOUR_PROJECT_ID',
  amount: '50.00',
  currency: 'USD',
  mode: 'iframe'
});

// Close the modal
PaymosWidget.close();

// Remove the button and clean up
PaymosWidget.destroy('#paymos-widget');

Eventos

El SDK despacha CustomEvent sobre window para que tu página reaccione al ciclo de vida del pago. Todos los datos viajan en event.detail.

Evento Cuándo se dispara event.detail
paymos:opened La ventana modal está montada y la URL del iframe ya está fijada. { url }
paymos:closed La ventana modal se ha eliminado (por cualquier motivo, incluido el temporizador opcional auto_close_delay). { reason: 'escape' | 'iframe' | 'replaced' | 'api' | 'success' }
paymos:succeeded El pago del cliente alcanzó paid o paid_over. Se emite desde dentro del iframe mediante postMessage. { invoiceId }
paymos:failed Estado final de fallo (underpaid, expired, cancelled). { invoiceId, reason }
paymos:error El SDK ni siquiera pudo crear la factura (red, autenticación, CORS o tiempo agotado). { message }

Los eventos succeeded y failed solo se disparan cuando la página de pago se abre en modo iframe: los entrega la propia página llamando a window.parent.postMessage. El SDK acepta un mensaje únicamente desde el origen de la URL de pago que incrustó y solo desde el contentWindow de ese iframe, así que ningún tercero presente en la página del comercio puede falsificarlos.

En el modo redirección la página se abandona antes de conocer el resultado, así que usa un webhook en tu servidor para confirmar la liquidación.

// 1. The customer paid — auto-close the modal and redirect to a thank-you page.
window.addEventListener('paymos:succeeded', (e) => {
  console.log('Paid:', e.detail.invoiceId);
  PaymosWidget.close();
  // Absolute and on your own domain: a root-relative path in a published
  // code sample gets crawled as one of OUR URLs — Googlebot did exactly that
  // and filed /thank-you?order= as a 404 against paymos.io.
  window.location.href = 'https://your-shop.example/thank-you?order=' + e.detail.invoiceId;
});

// 2. Payment failed (underpaid / expired / cancelled).
window.addEventListener('paymos:failed', (e) => {
  console.warn('Payment failed:', e.detail.invoiceId, e.detail.reason);
  // e.detail.reason: 'underpaid' | 'expired' | 'cancelled'
});

// 3. Modal lifecycle.
window.addEventListener('paymos:opened',  (e) => console.log('Opened',  e.detail.url));
window.addEventListener('paymos:closed',  (e) => console.log('Closed',  e.detail.reason));
//   e.detail.reason: 'escape' | 'iframe' | 'replaced' | 'api' | 'success'

// 4. Invoice creation failed (network down, bad config, server error).
window.addEventListener('paymos:error', (e) => {
  console.error('SDK error:', e.detail.message);
});

Allowed Origin

El SDK solo funciona en dominios que coincidan con el Allowed Origin configurado en los ajustes de tu widget. Las peticiones desde otros orígenes se rechazan.

Recurso al Terminal

El recurso al Terminal es opcional y hay que activarlo: apunta pos_url a tu página de Terminal. Cuando no se resuelve ningún importe válido (no hay amount, get_amount() devuelve null o el input de amount_selector está vacío), el SDK abre esa URL: un teclado numérico donde el importe se introduce a mano. Resulta útil en escenarios de punto de venta, donde el total cambia en cada transacción.

Si dejas pos_url sin definir, ese mismo caso lanza PaymosWidget requires an amount, amountSelector, or price_id., que llega a tu página como un evento paymos:error.