Developers API & Widget
ES

Pagos

Integración y widget de pagos

La integración de pagos con Wealth Reader se realiza en dos fases: preparación de la intención inmutable en su backend y montaje del widget seguro en el frontend.

La clave de API (X-API-Key) nunca debe aparecer en HTML, JavaScript de cliente, registros del navegador ni parámetros de URL.

1. Directorio de entidades bancarias

Para conocer qué bancos están disponibles y obtener sus logotipos, nombres y requisitos, puede consultar el endpoint de entidades directamente desde su backend. Cada entidad trae dos logotipos: logo, el que Wealth Reader recomienda mostrar (su propio logotipo vectorial cuando existe, el del proveedor en caso contrario, según logo_source), y logo_fallback, el del proveedor, para que su interfaz lo use si el primero no carga:

curl --request GET 'https://api.wealthreader.com/payments/entities/?country=ES'

Este endpoint es público: no envíe X-API-Key. Hacerlo no cambia la respuesta, consume una llamada de su cuota y, si los pagos estuvieran deshabilitados en su cuenta, convertiría una consulta que funciona en un 503.

También admite parámetros de consulta opcionales:

  • country: código de dos letras ISO (ej. ES, FR, DE, IT, PT...). Con ALL o vacío no se filtra por país.
  • search (alias q): búsqueda textual por nombre o código (ej. santander, bbva).
  • code: recupera una entidad concreta por su código exacto.
  • payment_method: filtra por método soportado (ej. sepa_credit_transfer).
  • limit y offset: paginación de resultados.

Respuesta abreviada de ejemplo:

{
  "success": true,
  "total": 2,
  "entities": [
    {
      "code": "santander-es",
      "name": "Banco Santander",
      "country": "ES",
      "logo": "https://cdn.wealthreader.com/santander.svg",
      "logo_fallback": "https://assets.exthand.com/bsdk/banks/logos/ES/santander.svg",
      "logo_source": "wealthreader",
      "payment_methods": ["sepa_credit_transfer", "instant_sepa_credit_transfer"],
      "requires_debtor_iban": false
    },
    {
      "code": "ebury-es",
      "name": "Ebury",
      "country": "ES",
      "logo": "https://assets.exthand.com/bsdk/banks/logos/ZZ/ebury.png",
      "logo_fallback": "https://assets.exthand.com/bsdk/banks/logos/ZZ/ebury.png",
      "logo_source": "exthand",
      "payment_methods": ["sepa_credit_transfer"],
      "requires_debtor_iban": true
    }
  ]
}

requires_debtor_iban es una capacidad observada por entidad, no una regla por país. Cuando vale false, el widget no solicita ni envía el IBAN de origen y el pagador elige la cuenta en la pantalla segura del banco. Cuando vale true, el widget exige el IBAN antes de redirigir. Las opciones de producción observadas el 10 de septiembre de 2026 confirman el valor false para Santander 976 en SEPA normal e instantáneo; todavía no se ha verificado mediante una SCA posterior al cambio la pantalla bancaria donde se selecciona la cuenta.

payment_methods describe las capacidades publicadas por la entidad. La demo demo-all-pay inicia actualmente solo SEPA normal; no ofrece un selector de prioridad ni inicia pagos instantáneos.

Patrón recomendado para mostrar el logotipo con respaldo automático:

<img src="https://cdn.wealthreader.com/santander.svg"
     data-fallback="https://assets.exthand.com/bsdk/banks/logos/ES/santander.svg"
     alt="Banco Santander" width="160" height="48"
     onerror="if (this.dataset.fallback && this.src !== this.dataset.fallback) { this.src = this.dataset.fallback; } else { this.hidden = true; }">

En /payments/entities/ ambos campos están siempre presentes y valen null cuando no existe logotipo. Las instituciones de POST /payments/?action=profile-institutions y del widget llevan los mismos logo y logo_fallback como campos opcionales: faltan cuando no hay logotipo utilizable. Los logotipos apuntan únicamente a cdn.wealthreader.com o assets.exthand.com; si su página tiene CSP, añada ambos hosts a img-src.

Perfiles administrados (como la demo de donativos): Si utiliza un perfil preconfigurado como cruz_roja_demo, consulte las instituciones y condiciones fijadas por el servidor llamando a POST /payments/?action=profile-institutions con el cuerpo {"profile": "cruz_roja_demo"}.

2. Crear una intención de pago en el backend

Cuando el cliente decide pagar en su checkout, su servidor genera una clave de idempotencia única y solicita la creación inmutable del pago a la API de Wealth Reader.

Modelo estándar para comercios (Propio beneficiario)

El comercio especifica su cuenta de cobro, el importe en céntimos (amount_minor), la referencia de pago y el origen web donde se cargará el widget:

: "${WR_API_KEY:?Defina WR_API_KEY en el entorno seguro de su backend}"
: "${WR_PAYMENT_IDEMPOTENCY_KEY:?Genere una clave UUID v4 o de alta entropía para este intento}"

curl --request POST 'https://api.wealthreader.com/payments/?action=create' \
  --header 'Content-Type: application/json' \
  --header "X-API-Key: ${WR_API_KEY}" \
  --header "Idempotency-Key: ${WR_PAYMENT_IDEMPOTENCY_KEY}" \
  --data '{
    "amount_minor": 1500,
    "currency": "EUR",
    "beneficiary": {
      "name": "Comercio Online S.L.",
      "iban": "ES9121000418450200051332"
    },
    "reference": "Pedido #78901",
    "customer_reference": "pedido-78901",
    "allowed_origin": "https://tienda.example.com",
    "allowed_institution_codes": ["santander-es", "bbva-es", "caixabank-es", "sabadell-es"],
    "locale": "es"
  }'

Nota: allowed_institution_codes es opcional. Si se omite, el usuario podrá elegir entre todas las entidades del catálogo.

Modelo con perfil administrado (Demostración de donativos)

Si integra el perfil administrado cruz_roja_demo:

curl --request POST 'https://api.wealthreader.com/payments/?action=create' \
  --header 'Content-Type: application/json' \
  --header "X-API-Key: ${WR_API_KEY}" \
  --header "Idempotency-Key: ${WR_PAYMENT_IDEMPOTENCY_KEY}" \
  --data '{
    "profile": "cruz_roja_demo",
    "institution_code": "santander-es",
    "amount_minor": 100,
    "customer_reference": "donativo-demo-0042",
    "allowed_origin": "https://tienda.example.com",
    "locale": "es",
    "expected_mode": "live"
  }'

Respuesta de la API

La API responde confirmando la intención inmutable y entregando los datos para inicializar el widget:

{
  "success": true,
  "payment": {
    "id": "11111111-1111-4111-8111-111111111111",
    "amount_minor": 1500,
    "currency": "EUR",
    "state": "ready",
    "interaction_status": "not_started",
    "payment_status": "not_initiated",
    "payment_attestation": {
      "mode": "live",
      "provider_binding": "PROVIDER_BINDING"
    },
    "widget": {
      "url": "https://widget.wealthreader.com/payments/",
      "token": "SHORT_LIVED_WIDGET_TOKEN",
      "expires_at": "2026-09-04T15:30:00+00:00"
    }
  }
}

Su backend debe entregar al navegador del usuario únicamente el payment.id y el payment.widget.token.

3. Montar el widget en el frontend

Existen dos formas de montar el widget en su interfaz web: mediante el script declarativo oficial o mediante la API programática de JavaScript.

Opción A: Vía script declarativo (load-payments.js)

Incruste el contenedor y el cargador en su página de checkout:

<div id="wr-payment-container"></div>

<script>
  document.querySelector('#wr-payment-container').addEventListener(
    'wealthreader:payment',
    (event) => {
      console.log('Evento de pago recibido:', event.detail.type, event.detail);

      if (event.detail.type === 'payment_status') {
        console.log('Estado actual:', event.detail.status);
      }

      if (event.detail.type === 'flow_closed') {
        // La interacción del usuario ha finalizado.
        // Consulte el estado financiero definitivo desde su backend.
      }
    }
  );
</script>

<script
  src="https://widget.wealthreader.com/js/load-payments.js"
  data-target="#wr-payment-container"
  data-payment-intent-id="11111111-1111-4111-8111-111111111111"
  data-widget-token="SHORT_LIVED_WIDGET_TOKEN"
  data-locale="es">
</script>

Opción B: Vía API de JavaScript (WealthReaderPayments.mount)

Si utiliza frameworks como React, Vue, Angular o un flujo SPA:

import { useEffect, useRef } from 'react';

// Cargue previamente https://widget.wealthreader.com/js/load-payments.js
const target = document.getElementById('wr-payment-container');

// Los eventos llegan como CustomEvent del DOM sobre el propio contenedor.
target.addEventListener('wealthreader:payment', (event) => {
  const detail = event.detail;
  if (detail.type === 'payment_status') {
    console.log('Estado del pago:', detail.status);
  }
  if (detail.type === 'flow_closed') {
    // Notificar al backend para comprobar la liquidación
  }
});

window.WealthReaderPayments.mount({
  target: target,
  paymentIntentId: '11111111-1111-4111-8111-111111111111',
  widgetToken: 'SHORT_LIVED_WIDGET_TOKEN',
  locale: 'es'
});

mount() no admite ningún callback: sus claves son target, paymentIntentId, widgetToken, locale, widgetOrigin y apiOrigin. Cualquier otra se descarta en silencio, así que un onEvent pasado en la configuración no daría error y tampoco se ejecutaría nunca. Escuche siempre el evento wealthreader:payment del contenedor.

El widget obtiene la configuración directamente de los servidores de Wealth Reader con el token de un solo uso. Si la entidad bancaria exige identificar la cuenta de cargo antes de redirigir, el widget solicita el IBAN deudor directamente al pagador sin que el comercio deba procesarlo. Si la capacidad es opcional, el widget omite ese dato y avisa de que la cuenta se elegirá en la pantalla segura del banco.

Eventos principales del widget

type Significado
ready El widget se ha inicializado y la información inmutable está disponible.
authorization_started El usuario ha iniciado la autorización bancaria (redirigido a SCA o app bancaria).
processing La autenticación bancaria ha finalizado y el sistema está procesando la operación.
payment_status Informa de un cambio en el estado del pago (pending, settled, rejected, etc.).
height_changed Ajuste dinámico de altura del iframe para evitar barras de desplazamiento.
flow_closed El usuario ha cerrado el widget o la interacción técnica ha terminado.

Recuerde que el evento flow_closed solo confirma el cierre de la ventana, no constituye confirmación de pago. Su backend siempre debe verificar el estado mediante la llamada server-to-server.

Siguiente paso

Revise Intenciones e idempotencia.

Última actualización