Saltearse al contenido
GitHub

Enviar una remesa con un monto de débito fijo.

Un pago de remesa es una transferencia de dinero de una persona a otra, normalmente entre países o a larga distancia, que a menudo implica una conversión de monedas. En esta guía, aprenderá cómo implementar una funcionalidad de pago único de remesa en la que sus usuarios puedan especificar exactamente cuánto quieren enviar, en lugar de cuánto debe recibir el destinatario.

Este enfoque es útil en particular para situaciones de aplicaciones de remesas en estos casos:

  • Sus usuarios quieren pagar un monto fijo desde su cuenta.
  • El destinatario recibe el monto que resulte después de la conversión de monedas.
  • Sus usuarios quieren evitar la complejidad de calcular las tarifas de conversión por adelantado.

Imagine que alguien en EE. UU. envía dinero a un familiar en México. Esta persona quiere enviar exactamente 100 dólares estadounidenses (USD) desde su cuenta, independientemente de cuánto reciba realmente su familiar después de que se apliquen los tipos de cambio. Esto difiere de los casos en los que el remitente especifica exactamente cuánto debe recibir el destinatario.

Para esta guía, asumirá el papel de un desarrollador que está creando una aplicación de remesas. La guía explica cómo enviar un pago de $100 USD, en el que el remitente paga exactamente $100, y el destinatario recibe el monto en pesos mexicanos (MXN) después de la conversión de monedas.

Detalles de la transacción de ejemplo:

  • El remitente paga: $100.00 USD (monto exacto)
  • Conversión de moneda: USD a MXN a un tipo de cambio de 17.00
  • El destinatario recibe: $1,700 MXN ($100 × 17.00)

Las tres partes que intervienen en este caso son las siguientes:

  • Desarrollador: usted, la persona que construye la aplicación de remesas.
  • Remitente: la persona que utiliza su aplicación para enviar dinero en USD.
  • Destinatario: la persona que recibe el dinero en MXN.

Recuerde que Open Payments no ejecuta pagos ni toca dinero de ninguna manera. Se usa para emitir instrucciones de pago antes de que se produzca cualquier movimiento de dinero. Un ejemplo de una instrucción de pago es: “debitar exactamente $100 de la cuenta del remitente y enviar el monto a la cuenta del destinatario después de que se apliquen los tipos de cambio”.

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 remitente inicia un pago a través de su aplicación de remesas, usted necesita obtener la información de la dirección de billetera tanto del remitente como del destinatario.

Asumamos que el remitente ya ha proporcionado su propia dirección de billetera cuando se registró para usar su aplicación. Asumamos también que el remitente ingresó la dirección de billetera del destinatario en el formulario de pago de su aplicación al iniciar el pago.

Llame a la GET Get Wallet Address API para cada dirección.

const senderWalletAddress = await client.walletAddress.get({
url: 'https://cloudninebank.example.com/sender'
})
const recipientWalletAddress = await client.walletAddress.get({
url: 'https://happylifebank.example.com/recipient'
})

Respuestas de ejemplo El siguiente ejemplo muestra una respuesta del proveedor de billetera del remitente.

{
"id": "https://cloudninebank.example.com/sender",
"assetCode": "USD",
"assetScale": 2,
"authServer": "https://auth.cloudninebank.example.com/",
"resourceServer": "https://cloudninebank.example.com/op"
}

El siguiente ejemplo muestra una respuesta del proveedor de billetera del destinatario.

{
"id": "https://happylifebank.example.com/recipient",
"assetCode": "MXN",
"assetScale": 2,
"authServer": "https://auth.happylifebank.example.com/",
"resourceServer": "https://happylifebank.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 destinatario authServer, recibidos en el paso anterior, para llamar a la POST Grant Request API.

Esta llamada obtiene un token de acceso que permite a su aplicación solicitar la creación de un recurso de pago entrante en la cuenta de billetera del destinatario.

const recipientIncomingPaymentGrant = await client.grant.request(
{
url: recipientWalletAddress.authServer
},
{
access_token: {
access: [
{
type: "incoming-payment",
actions: ["create"],
},
],
},
},
);

Ejemplo de respuesta El siguiente ejemplo muestra una respuesta del proveedor de billetera del destinatario.

{
"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 Incoming Payment API.

Esta llamada solicita la creación de un recurso de pago entrante en la cuenta de billetera del destinatario.

const recipientIncomingPayment = await client.incomingPayment.create(
{
url: recipientWalletAddress.resourceServer,
accessToken: recipientIncomingPaymentGrant.access_token.value
},
{
walletAddress: recipientWalletAddress.id
},
)

Ejemplo de respuesta El siguiente ejemplo muestra una respuesta del proveedor de billetera del destinatario.

{
"id": "https://happylifebank.example.com/incoming-payments/{...}",
"walletAddress": "https://happylifebank.example.com/recipient",
"receivedAmount": {
"value": "0",
"assetCode": "USD",
"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 remitente authServer recibidos en el paso 1 para llamar a la POST Grant Request API.

Esta llamada obtiene un token de acceso que permite a su aplicación solicitar la creación de un recurso de cotización en la cuenta de billetera del remitente.

const senderQuoteGrant = await client.grant.request(
{
url: senderWalletAddress.authServer
},
{
access_token: {
access: [
{
type: 'quote',
actions: ['create']
}
]
}
}
)
Ejemplo de respuesta
{
"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 remitente. La solicitud debe contener el receiver, que es la id del pago entrante del destinatario, junto con el debitAmount, que es el monto exacto que el remitente desea pagar.

El debitAmount especifica que el remitente pagará exactamente $100 USD, y el destinatario recibirá cualquier monto que quede después de la conversión de monedas.

const senderQuote = await client.quote.create(
{
url: senderWalletAddress.resourceServer,
accessToken: senderQuoteGrant.access_token.value
},
{
method: 'ilp',
walletAddress: senderWalletAddress.id,
receiver: recipientIncomingPayment.id,
debitAmount: {
value: '10000',
assetCode: 'USD',
assetScale: 2
}
}
)

La respuesta devuelve un receiveAmount, un debitAmount y demás información requerida.

  • debitAmount: el monto que el remitente debe pagar (exactamente $100.00 USD en nuestro ejemplo).
  • receiveAmount: el monto que el destinatario recibirá realmente ($1,700.00 MXN en nuestro ejemplo) después de la conversión de monedas.

Ejemplo de respuesta El siguiente ejemplo muestra una respuesta del proveedor de billetera del remitente.

{
"id": "https://cloudninebank.example.com/quotes/{...}", // url identifying the quote
"walletAddress": "https://cloudninebank.example.com/sender",
"receiver": "https://happylifebank.example.com/incoming-payments/{...}", // url of the incoming payment the quote is created for
"debitAmount": {
"value": "10000", // Sender pays exactly $100.00 USD
"assetCode": "USD",
"assetScale": 2
},
"receiveAmount": {
"value": "170000", // Recipient receives $1,700.00 MXN after currency conversion
"assetCode": "MXN",
"assetScale": 2
},
"method": "ilp",
"createdAt": "2025-03-12T23:22:51.50Z",
"expiresAt": "2025-03-12T23:24: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 remitente authServer recibida en el paso 1 para llamar a la POST Grant Request API.

Esta llamada obtiene un token de acceso que permite a su aplicación solicitar la creación de un recurso de pago saliente en la cuenta de billetera del remitente.

const pendingSenderOutgoingPaymentGrant = await client.grant.request(
{
url: senderWalletAddress.authServer
},
{
access_token: {
access: [
{
identifier: senderWalletAddress.id,
type: 'outgoing-payment',
actions: ['create'],
limits: {
debitAmount: {
assetCode: 'USD',
assetScale: 2,
value: '10000',
}
}
}
]
},
interact: {
start: ['redirect'],
finish: {
method: 'redirect',
uri: 'https://myapp.example.com/finish/{...}', // where to redirect your user after they've completed the interaction
nonce: NONCE
}
}
}
)
Ejemplo de respuesta
{
"interact": {
"redirect": "https://auth.cloudninebank.example.com/{...}", // uri to redirect the sender 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.cloudninebank.example.com/continue/{...}", // uri for continuing the outgoing payment grant request
"wait": 30
}
}

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»

En nuestro ejemplo, suponemos que el IdP con el que interactuó su usuario cuenta con una interfaz de usuario. Cuando la interacción finaliza, el usuario regresa a su aplicación. Ahora su 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 su aplicación solicitar la creación de un recurso de pago saliente en la cuenta de billetera del remitente.

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 senderOutgoingPaymentGrant = await client.grant.continue(
{
url: pendingSenderOutgoingPaymentGrant.continue.uri,
accessToken: pendingSenderOutgoingPaymentGrant.continue.access_token.value
},
{
interact_ref: interactRef
}
)
Ejemplo de respuesta
{
"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", "read"],
"identifier": "https://cloudninebank.example.com/sender",
"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. Incluya el quoteId en la solicitud. La quoteId es la id devuelta en la respuesta de Create Quote API (paso 5).

const senderOutgoingPayment = await client.outgoingPayment.create(
{
url: senderWalletAddress.resourceServer,
accessToken: senderOutgoingPaymentGrant.access_token.value
},
{
walletAddress: senderWalletAddress.id,
quoteId: senderQuote.id
}
)

Ejemplo de respuesta El siguiente ejemplo muestra una respuesta cuando se crea un recurso de pago saliente en la cuenta del remitente.

{
"id": "https://cloudninebank.example.com/outgoing-payments/{...}", // url identifying the outgoing payment
"walletAddress": "https://cloudninebank.example.com/sender",
"receiver": "https://happylifebank.example.com/incoming-payments/{...}", // url of the incoming payment being paid
"debitAmount": {
"value": "10000", // Sender pays exactly $100.00 USD
"assetCode": "USD",
"assetScale": 2
},
"receiveAmount": {
"value": "170000", // Recipient receives $1,700.00 MXN after currency conversion
"assetCode": "MXN",
"assetScale": 2
},
"sentAmount": {
"value": "0",
"assetCode": "USD",
"assetScale": 2
},
"createdAt": "2022-03-12T23:20:54.52Z"
}