Saltearse al contenido
GitHub

Realizar pagos recurrentes

Las API de Open Payments facilitan múltiples casos de uso para pagos recurrentes hacia y desde billeteras compatibles con Open Payments. “Compre ahora y pague después” (Buy Now Pay Later, BNPL) es un ejemplo, en el que un comprador paga un artículo en cuotas a lo largo de intervalos programados de manera regular.

En esta guía, encontrará pasos para realizar pagos recurrentes, en los que una única concesión de pago saliente se utiliza para crear varios recursos de pago saliente en intervalos definidos.

Import dependencies

import { createAuthenticatedClient } from "@interledger/open-payments";
Copied!

Initialize Open Payments client

const client = await createAuthenticatedClient({
  walletAddressUrl: WALLET_ADDRESS,
  privateKey: PRIVATE_KEY_PATH,
  keyId: KEY_ID,
});
Copied!

1. Obtener los datos de la dirección de billetera del destinatario

Sección titulada «1. Obtener los datos de la dirección de billetera del destinatario»

Get wallet address information

const walletAddress = await client.walletAddress.get({
  url: WALLET_ADDRESS,
});
Copied!

2. Solicitar una concesión de autorización para un pago entrante

Sección titulada «2. Solicitar una concesión de autorización para un pago entrante»

Solicitar una concesión de autorización para un incomingPayment desde el servidor de autorización de la billetera del destinatario.

Request incoming payment grant

const grant = await client.grant.request(
  {
    url: walletAddress.authServer,
  },
  {
    access_token: {
      access: [
        {
          type: "incoming-payment",
          actions: ["list", "read", "read-all", "complete", "create"],
        },
      ],
    },
  },
);
Copied!

Crear un incomingPayment en el servidor de recursos de la billetera del destinatario mediante el uso del token de acceso que devolvió el servidor de autorización en la solicitud de concesión de autorización y especificar la walletAddress con la URL de la billetera del destinatario.

Agregar el objeto incomingAmount y definir las siguientes propiedades:

  • value : el monto máximo permitido que se pagará a la dirección de billetera del destinatario.
  • assetCode: el código que representa el activo subyacente utilizado para efectuar el pago. Siempre que sea posible, se debe utilizar un código de divisa que siga la norma ISO 4217. Por ejemplo, el código de divisa que la norma ISO 4217 establece para el dólar estadounidense es “USD”.
  • assetScale: la cantidad de números decimales que define la escala de la unidad más pequeña para el código de activos dado. Determina cómo se escala un monto entero para obtener el valor monetario real. Por ejemplo, el USD tiene una escala de activo de 2 y la unidad más pequeña es 0,01. Un monto entero de 1000 con un assetCode de USD y una assetScale de 2 se transforma en USD 10,00.

De modo opcional, puede agregar la propiedad expiresAt, que es la fecha y la hora a partir de la que ya no se aceptarán pagos entrantes.

Create incoming payment

const incomingPayment = await client.incomingPayment.create(
  {
    url: new URL(WALLET_ADDRESS).origin,
    accessToken: INCOMING_PAYMENT_ACCESS_TOKEN,
  },
  {
    walletAddress: WALLET_ADDRESS,
    incomingAmount: {
      value: "1000",
      assetCode: "USD",
      assetScale: 2,
    },
    expiresAt: new Date(Date.now() + 60_000 * 10).toISOString(),
  },
);
Copied!

4. Solicitar una concesión de autorización para una cotización

Sección titulada «4. Solicitar una concesión de autorización para una cotización»

Solicitar una concesión de autorización para una quote desde el servidor de autorización de la billetera del remitente.

Request quote grant

const grant = await client.grant.request(
  {
    url: walletAddress.authServer,
  },
  {
    access_token: {
      access: [
        {
          type: "quote",
          actions: ["create", "read", "read-all"],
        },
      ],
    },
  },
);
Copied!

Crear una quote en el servidor de recursos de la billetera del remitente mediante el uso del token de acceso que devolvió el servidor de autorización en la solicitud de concesión de autorización.

Agregar las siguientes propiedades:

  • method: el método de pago que se utiliza para facilitar el pago. Configurar esta propiedad en ilp, ya que Open Payments solo admite pagos de Interledger en la actualidad.
  • walletAddress: la URL de la dirección de billetera del remitente.
  • receiver: la URL del pago entrante que recibirá el pago.

Create quote

const quote = await client.quote.create(
  {
    url: new URL(WALLET_ADDRESS).origin,
    accessToken: QUOTE_ACCESS_TOKEN,
  },
  {
    method: "ilp",
    walletAddress: WALLET_ADDRESS,
    receiver: INCOMING_PAYMENT_URL,
  },
);
Copied!

6. Solicitar una concesión de autorización interactiva para un pago saliente

Sección titulada «6. Solicitar una concesión de autorización interactiva para un pago saliente»

Solicitar una concesión de autorización para un outgoingPayment desde el servidor de autorización de la billetera del remitente. Esta solicitud requiere una concesión de autorización interactiva, ya que el remitente tendrá que expresar su consentimiento antes de que se efectúe un outgoingPayment de su billetera.

Agregar el objeto limits con una de las siguientes propiedades:

  • debitAmount: el monto máximo que se deducirá de la billetera del remitente.
  • receiveAmount: el monto máximo que recibirá la billetera del destinatario.

Luego agregue la propiedad interval al objeto limits, que es el período de intervalo conforme al formato de cadena de intervalos repetidos ISO8601.

A continuación, indique que su cliente es capaz de direccionar al usuario a una URI para iniciar una interacción.

  1. Agregar el objeto interact a su solicitud de concesión de autorización.
  2. Especificar redirect como el modo de start. En la actualidad, Open Payments solo admite redirect. El servidor de autorización proporcionará la URL de redirección en su respuesta.

Ahora indique que su cliente puede recibir una señal del servidor de autorización una vez que la interacción haya finalizado.

  1. Agregar el objeto finish dentro del objeto interact.
  2. Especificar redirect como method. En la actualidad, Open Payments solo admite redirect.
  3. Especificar la uri que el servidor de autorización le enviará al usuario una vez que la interacción haya finalizado.
  4. Crear un nonce para que su cliente lo utilice a la hora de verificar que el servidor de autorización sea la misma entidad a lo largo de todo el proceso. Este código puede ser cualquier cadena aleatoria y difícil de descifrar.

Request outgoing payment grant

const grant = await client.grant.request(
  {
    url: walletAddress.authServer,
  },
  {
    access_token: {
      access: [
        {
          identifier: walletAddress.id,
          type: "outgoing-payment",
          actions: ["list", "list-all", "read", "read-all", "create"],
          limits: {
            debitAmount: {
              assetCode: quote.debitAmount.assetCode,
              assetScale: quote.debitAmount.assetScale,
              value: quote.debitAmount.value,
            },
          },
        },
      ],
    },
    interact: {
      start: ["redirect"],
      finish: {
        method: "redirect",
        uri: "http://localhost:3344",
        nonce: NONCE,
      },
    },
  },
);
Copied!

Check grant state

if (!isPendingGrant(grant)) {
  throw new Error("Expected interactive grant");
}
Copied!

Una vez que el cliente recibe la respuesta del servidor de autorización, debe enviar al usuario al URI de interact.redirect de la respuesta. Esto da comienzo al flujo de interacción.

La respuesta también incluye un objeto de continue, que es fundamental para gestionar la interacción y obtener el consentimiento explícito del usuario para concesiones de autorizaciones de pagos salientes. El objeto de continue contiene un token de acceso y un URI que el cliente usará para finalizar la solicitud de concesión de autorización después de que el usuario haya completado su interacción con el proveedor de identidad (Identity provider, IdP). Esto asegura que el cliente pueda obtener de manera segura los permisos necesarios para proceder con el proceso de pago.

Respuesta de ejemplo
{
"interact": {
"redirect": "https://auth.interledger-test.dev/4CF492MLVMSW9MKMXKHQ",
"finish": "4105340a-05eb-4290-8739-f9e2b463bfa7"
},
"continue": {
"access_token": {
"value": "33OMUKMKSKU80UPRY5NM"
},
"uri": "https://auth.interledger-test.dev/continue/4CF492MLVMSW9MKMXKHQ",
"wait": 30
}
}

El usuario interactúa con el servidor de autorización a través de la interfaz del servidor y aprueba o rechaza la concesión de autorización.

Siempre que el usuario apruebe la concesión de autorización, el servidor de autorización realiza lo siguiente:

  • Envía al usuario al finish.uri anteriormente definido por su cliente. La manera en que el servidor envía al usuario al URI está fuera de alcance, pero las opciones comunes incluyen redireccionar al usuario desde una página web y lanzar el navegador del sistema con la URI específica.
  • Asegura la redirección al agregar un hash único, lo que le permite a su cliente validar la llamada de finish, y una referencia de interacción como parámetros de consulta al URI.

9. Solicitar una continuación de la concesión de autorización

Sección titulada «9. Solicitar una continuación de la concesión de autorización»

Una vez que el usuario completó su interacción con el proveedor de identidad (identity provider, IdP), debe ser redirigido de vuelta a la aplicación. Ahora puede hacer la solicitud de continuación de la solicitud de concesión. En situaciones donde una interfaz de usuario no se encuentra disponible, analice la posibilidad de implementar un mecanismo de sondeo para verificar que se haya completado la interacción.

Agregue la referencia a la interacción del servidor de autorización como el valor interact_ref al cuerpo de su solicitud de continuación.

Continue grant

const grant = await client.grant.continue(
  {
    accessToken: CONTINUE_ACCESS_TOKEN,
    url: CONTINUE_URI,
  },
  {
    interact_ref: interactRef,
  },
);
Copied!

Emita la solicitud para la continue uri que se proporcionó en la respuesta inicial de la concesión que devolvió el servidor de autorización. Por ejemplo:

POST https://auth.interledger-test.dev/continue/4CF492MLVMSW9MKMXKHQ

En una respuesta de continuación correcta del servidor de autorización, se proporciona a su cliente el token de acceso y otra información necesaria para continuar con la transacción.

Respuesta de ejemplo
{
"access_token": {
"value": "OS9M2PMHKUR64TB8N6BW7OZB8CDFONP219RP1LT0",
"manage": "https://auth.interledger-test.dev/token/dd17a202-9982-4ed9-ae31-564947fb6379",
"expires_in": 3600,
"access": [
{
"type": "outgoing-payment",
"actions": ["create", "read", "read-all", "list", "list-all"],
"identifier": "https://ilp.interledger-test.dev/alice",
"limits": {
"receiver": "https://ilp.interledger-test.dev/bob/incoming-payments/48884225-b393-4872-90de-1b737e2491c2",
"interval": "R12/2019-08-24T14:15:22Z/P1M",
"debitAmount": {
"value": "500",
"assetCode": "USD",
"assetScale": 2
}
}
}
]
},
"continue": {
"access_token": {
"value": "33OMUKMKSKU80UPRY5NM"
},
"uri": "https://auth.interledger-test.dev/continue/4CF492MLVMSW9MKMXKHQ",
"wait": 30
}
}

Cree un outgoingPayment en el servidor de recursos de la billetera del remitente mediante el uso del token de acceso que devolvió el servidor de autorización en la solicitud de concesión de autorización.

Agregar las siguientes propiedades:

  • walletAddress: la URL de la dirección de billetera del remitente.
  • quoteId: la URL de la cotización en la que se especifica el monto del pago.

Create outgoing payment

const outgoingPayment = await client.outgoingPayment.create(
  {
    url: new URL(WALLET_ADDRESS).origin,
    accessToken: OUTGOING_PAYMENT_ACCESS_TOKEN,
  },
  {
    walletAddress: WALLET_ADDRESS,
    quoteId: QUOTE_URL,
  },
);
Copied!

Rote el token de acceso obtenido en la solicitud de concesión outgoingPayment anterior.

Rotate token

const token = await client.token.rotate({
  url: MANAGE_URL,
  accessToken: ACCESS_TOKEN,
});
Copied!

Cree otro outgoingPayment en el servidor de recursos de la billetera del remitente utilizando el nuevo token de acceso que devolvió el servidor de autorización en el paso anterior.

Agregar las siguientes propiedades:

  • walletAddress: la URL de la dirección de billetera del remitente.
  • quoteId: la URL de la cotización en la que se especifica el monto del pago.

Create outgoing payment

const outgoingPayment = await client.outgoingPayment.create(
  {
    url: new URL(WALLET_ADDRESS).origin,
    accessToken: OUTGOING_PAYMENT_ACCESS_TOKEN,
  },
  {
    walletAddress: WALLET_ADDRESS,
    quoteId: QUOTE_URL,
  },
);
Copied!

13. Cómo realizar pagos salientes recurrentes

Sección titulada «13. Cómo realizar pagos salientes recurrentes»

Repita los pasos 11 y 12 para facilitar tantos pagos como necesite su aplicación.