Aceptar un pago único por una compra en línea
En un modelo de negocio a consumidor (business-to-consumer, B2C), las empresas venden sus productos directamente a los consumidores y evitan cualquier intermediario. Este modelo también se denomina directo al consumidor (direct-to-consumer, D2C).
Los minoristas en línea suelen utilizar el modelo B2C y permiten a los clientes pagar directamente por los bienes y servicios. En los casos en que un intermediario o un tercero deba recibir una parte de la venta, el pago puede dividirse.
Caso hipotético
Sección titulada «Caso hipotético»Para esta guía, asumirá el papel de un desarrollador que trabaja para una empresa de artículos deportivos en línea. Un cliente agrega un par de zapatillas a su carrito de compras e inicia el proceso de pago. El total es de MXN 1400. En esta guía, se explica cómo puede implementar Open Payments en el sitio web del minorista para que este reciba el monto total del pago del cliente.
Las partes que intervienen en la transacción son las siguientes:
- Minorista: la empresa de artículos deportivos
- Desarrollador: usted, como el desarrollador que trabaja en la aplicación cliente
- Aplicación cliente: el sitio web del minorista
- Cliente: la persona que utiliza el sitio web del minorista para hacer una compra
Puntos finales
Sección titulada «Puntos finales»- GET Get Wallet Address
- POST Grant Request
- POST Create an Incoming Payment
- POST Create a Quote
- POST Grant Continuation Request
- POST Create an Outgoing Payment
1. Obtener los datos de la dirección de billetera
Sección titulada «1. Obtener los datos de la dirección de billetera»Cuando el cliente inicia el pago, la aplicación cliente (el sitio web del minorista) debe obtener la información de la dirección de billetera tanto del cliente como la propia.
Asumamos que el cliente ingresó su dirección de billetera en el formulario de pago del sitio. Asumamos también que la dirección de billetera del minorista está codificada en dicho formulario de pago.
Llame a la GET Get Wallet Address API para cada dirección.
const customerWalletAddress = await client.walletAddress.get({ url: 'https://cloudninebank.example.com/customer'})const retailerWalletAddress = await client.walletAddress.get({ url: 'https://happylifebank.example.com/retailer'})Ejemplo de respuesta
El siguiente es un ejemplo de respuesta proveniente del proveedor de billetera del cliente. El proveedor de billetera del minorista devolverá una respuesta similar.
{ "id": "https://cloudninebank.example.com/customer", "assetCode": "USD", "assetScale": 2, "authServer": "https://auth.cloudninebank.example.com/", "resourceServer": "https://cloudninebank.example.com/op"}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»Utilice los datos del minorista authServer, recibidos en el paso anterior, para llamar a la POST Grant Request API.
Esta llamada obtiene un token de acceso que permite a la aplicación cliente solicitar la creación de un recurso de pago entrante en la cuenta de billetera del minorista.
const retailerIncomingPaymentGrant = await client.grant.request( { url: retailerWalletAddress.authServer }, { access_token: { access: [ { type: 'incoming-payment', actions: ['create'], }, ], }, },);Ejemplo de respuesta
El siguiente es un ejemplo de respuesta proveniente del proveedor de billetera del minorista.
{ "access_token": { "value": "...", // access token value for incoming payment grant "manage": "https://auth.happylifebank.example.com/token/{...}", // management uri for access token "access": [ { "type": "incoming-payment", "actions": ["create"] } ] }, "continue": { "access_token": { "value": "..." // access token for continuing the request }, "uri": "https://auth.happylifebank.example.com/continue/{...}" // continuation request uri }}3. Solicitar la creación de un recurso de pago entrante
Sección titulada «3. Solicitar la creación de un recurso de pago entrante»Use el token de acceso devuelto en la respuesta anterior para llamar a la POST Create an Incoming Payment API.
Esta llamada solicita la creación de un recurso de pago entrante en la cuenta de billetera del minorista.
Recuerde que el monto total de la compra del cliente es de MXN 1400.
const retailerIncomingPayment = await.client.incomingPayment.create( { url: retailerWalletAddress.resourceServer, accessToken: retailerIncomingPaymentGrant.access_token.value }, { walletAddress: retailerWalletAddress.id, incomingAmount: { value: '140000', assetCode: 'MXN', assetScale: 2 }, },)Ejemplo de respuesta
El siguiente es un ejemplo de respuesta proveniente del proveedor de billetera del minorista.
{ "id": "https://happylifebank.example.com/incoming-payments/{...}", "walletAddress": "https://happylifebank.example.com/retailer", "incomingAmount": { "value": "140000", "assetCode": "MXN", "assetScale": 2 }, "receivedAmount": { "value": "0", "assetCode": "MXN", "assetScale": 2 }, "completed": false, "createdAt": "2025-03-12T23:20:50.52Z", "methods": [ { "type": "ilp", "ilpAddress": "...", "sharedSecret": "..." } ]}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»Utilice los datos del consumidor authServer, devueltos en el paso 1, para llamar a la POST Grant Request API.
Esta llamada obtiene un token de acceso que permite a la aplicación cliente solicitar la creación de un recurso de cotización en la cuenta de billetera del cliente.
const customerQuoteGrant = await client.grant.request( { url: customerWalletAddress.authServer }, { access_token: { access: [ { type: 'quote', actions: ['create'] } ] } })Ejemplo de respuesta
El siguiente es un ejemplo de respuesta proveniente del proveedor de billetera del cliente.
{ "access_token": { "value": "...", // access token value for quote grant "manage": "https:/auth.cloudninebank.example.com/token/{...}", // management uri for access token "access": [ { "type": "quote", "actions": ["create"] } ] }, "continue": { "access_token": { "value": "..." // access token for continuing the request }, "uri": "https://auth.cloudninebank.example.com/continue/{...}" // continuation request uri }}5. Solicitar la creación de un recurso de cotización
Sección titulada «5. Solicitar la creación de un recurso de cotización»Utilice el token de acceso recibido en el paso anterior para llamar a la POST Create Quote API.
Esta llamada solicita la creación de un recurso de cotización en la cuenta de la billetera del consumidor.
La solicitud debe contener el destinatario, que es la id del pago entrante. La id se indicó en la respuesta de la Create an Incoming Payment API en el paso 3.
const customerQuote = await client.quote.create( { url: customerWalletAddress.resourceServer, accessToken: customerQuoteGrant.access_token.value }, { method: 'ilp', walletAddress: customerWalletAddress.id, receiver: retailerIncomingPayment.id })La respuesta devuelve un receiveAmount, un debitAmount y demás información requerida.
debitAmount: el monto (expresado en MXN) que se cobrará al cliente.receiveAmount: el valor delincomingAmountdel recurso de pago entrante.
Ejemplo de respuesta
El siguiente es un ejemplo de respuesta proveniente del proveedor de billetera del cliente.
{ "id": "https://cloudninebank.example.com/quotes/{...}", // url identifying the quote "walletAddress": "https://cloudninebank.example.com/customer", "receiver": "https://happylifebank.example.com/incoming-payments/{...}", // url of the incoming payment the quote is created for "debitAmount": { "value": "140000", "assetCode": "MXN", "assetScale": 2 }, "receiveAmount": { "value": "140000", "assetCode": "MXN", "assetScale": 2 }, "method": "ilp", "createdAt": "2025-03-12T23:22:51.50Z"}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»Utilice la información del consumidor authServer para llamar a la POST Grant Request.
Esta llamada obtiene un token de acceso que permite a la aplicación cliente solicitar la creación de recursos de pago saliente en la cuenta de billetera del cliente. Para esta guía, la solicitud se limitará hasta el monto de 140000 (MXN 1400,00).
const pendingCustomerOutgoingPaymentGrant = await client.grant.request( { url: customerWalletAddress.authServer }, { access_token: { access: [ { identifier: customerWalletAddress.id, type: 'outgoing-payment', actions: ['create'], limits: { debitAmount: { assetCode: 'MXN', assetScale: 2, value: '140000', } } } ] }, interact: { start: ['redirect'], finish: { method: 'redirect', uri: 'https://paymentplatform.example/finish/{...}', // where to redirect the customer after they've completed the interaction nonce: NONCE } } })Ejemplo de respuesta
El siguiente es un ejemplo de respuesta proveniente del proveedor de billetera del cliente.
{ "interact": { "redirect": "https://auth.interledger-test.dev/{...}", // uri to redirect the customer to, to begin interaction "finish": "..." // unique key to secure the callback }, "continue": { "access_token": { "value": "..." // access token for continuing the outgoing payment grant request }, "uri": "https://auth.interledger-test.dev/continue/{...}", // uri for continuing the outgoing payment grant request "wait": 30 }}7. Comenzar la interacción con el consumidor
Sección titulada «7. Comenzar la interacción con el consumidor»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.
{ "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 }}8. Finalizar la interacción con el consumidor
Sección titulada «8. Finalizar la interacción con el consumidor»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.urianteriormente 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»En nuestro ejemplo, suponemos que el IdP con el que interactuó el consumidor cuenta con una interfaz de usuario. Cuando la interacción finaliza, el consumidor regresa a la aplicación cliente. Ahora la aplicación puede realizar una solicitud de continuación de la concesión de autorización de pago saliente.
Llame a la POST Grant Continuation Request API. Esta llamada solicita un token de acceso que permite a la aplicación cliente solicitar la creación de un recurso de pago saliente en la cuenta de billetera del cliente.
Emita la solicitud al continue.uri proporcionado en la respuesta de concesión de autorización de pago saliente inicial (paso 6).
Incluya la interact_ref devuelta en los parámetros de consulta del URI de redirección.
const customerOutgoingPaymentGrant = await client.grant.continue( { url: pendingCustomerOutgoingPaymentGrant.continue.uri, accessToken: pendingCustomerOutgoingPaymentGrant.continue.access_token.value }, { interact_ref: interactRef })Ejemplo de respuesta
El siguiente es un ejemplo de respuesta proveniente del proveedor de billetera del cliente.
{ "access_token": { "value": "...", // final access token required before creating outgoing payments "manage": "https://auth.cloudninebank.example.com/token/{...}", // management uri for access token "access": [ { "type": "outgoing-payment", "actions": ["create"], "identifier": "https://cloudninebank.example.com/customer", "limits": { "receiver": "https://happylifebank.example.com/incoming-payments/{...}" // url of the incoming payment that's being paid } } ] }, "continue": { "access_token": { "value": "..." // access token for continuing the request }, "uri": "https://auth.cloudninebank.example.com/continue/{...}" // continuation request uri }}10. Solicitar la creación de un recurso de pago saliente
Sección titulada «10. Solicitar la creación de un recurso de pago saliente»Utilice el token de acceso devuelto en el paso 9 para llamar a la POST Create Outgoing Payment API. Esta llamada solicita la creación de un recurso de pago saliente en la cuenta de billetera del consumidor. Incluya el quoteId en la solicitud. La quoteId es la id devuelta en la respuesta de Create Quote API (paso 5).
const customerOutgoingPayment = await client.outgoingPayment.create( { url: customerWalletAddress.resourceServer, accessToken: customerOutgoingPaymentGrant.access_token.value }, { walletAddress: customerWalletAddress.id, quoteId: customerQuote.id })Ejemplo de respuesta
El siguiente es un ejemplo de respuesta proveniente del proveedor de billetera del cliente.
{ "id": "https://cloudninebank.example.com/outgoing-payments/{...}", // url identifying the outgoing payment "walletAddress": "https://cloudninebank.example.com/customer", "receiver": "https://happylifebank.example.com/incoming-payments/{...}", // url of the incoming payment being paid "debitAmount": { "value": "140000", "assetCode": "MXN", "assetScale": 2 }, "receiveAmount": { "value": "140000", "assetCode": "MXN", "assetScale": 2 }, "sentAmount": { "value": "0", "assetCode": "MXN", "assetScale": 2 }, "createdAt": "2022-03-12T23:20:54.52Z"}