From a3b883ce28d0eb9155ade5ba202f256221385195 Mon Sep 17 00:00:00 2001
From: hajjimo <96056726+hajjimo@users.noreply.github.com>
Date: Mon, 6 Apr 2026 20:16:14 +0100
Subject: [PATCH] docs: mi-snippets-partials
Move code examples into partials
---
.../es/guides/accept-otp-online-purchase.mdx | 838 +---------
.../guides/onetime-remittance-fixed-debit.mdx | 836 +---------
.../onetime-remittance-fixed-receive.mdx | 846 +----------
.../guides/outgoing-grant-future-payments.mdx | 348 +----
.../recurring-remittance-fixed-debit.mdx | 644 +-------
.../recurring-remittance-fixed-receive.mdx | 852 +----------
...recurring-subscription-incoming-amount.mdx | 851 +----------
.../content/docs/es/guides/split-payments.mdx | 1086 +------------
.../guides/accept-otp-online-purchase.mdx | 1016 +------------
.../guides/onetime-remittance-fixed-debit.mdx | 1021 +------------
.../onetime-remittance-fixed-receive.mdx | 1035 +------------
.../guides/outgoing-grant-future-payments.mdx | 403 +----
.../recurring-remittance-fixed-debit.mdx | 780 +---------
.../recurring-remittance-fixed-receive.mdx | 1031 +------------
...recurring-subscription-incoming-amount.mdx | 1033 +------------
.../content/docs/guides/split-payments.mdx | 1342 +----------------
.../_create-incoming-payment.mdx | 121 ++
.../_create-outgoing-payment.mdx | 114 ++
.../_create-quote.mdx | 117 ++
.../_get-wallet-address.mdx | 75 +
.../_grant-continuation-request.mdx | 103 ++
.../_grant-request-incoming-payment.mdx | 129 ++
.../_grant-request-outgoing-payment.mdx | 216 +++
.../_grant-request-quote.mdx | 128 ++
.../_create-incoming-payment-open.mdx | 102 ++
.../_create-outgoing-payment.mdx | 112 ++
.../_create-quote-debit-amount.mdx | 133 ++
.../_get-wallet-address.mdx | 75 +
.../_grant-request-incoming-payment.mdx | 122 ++
.../_grant-request-outgoing-payment.mdx | 235 +++
.../_grant-request-quote.mdx | 123 ++
.../_request-a-grant-continuation.mdx | 98 ++
.../_create-incoming-payment.mdx | 105 ++
.../_create-outgoing-payment.mdx | 113 ++
.../_create-quote-ilp.mdx | 134 ++
.../_get-wallet-address.mdx | 75 +
.../_grant-request-incoming-payment.mdx | 126 ++
.../_grant-request-outgoing-payment.mdx | 226 +++
.../_grant-request-quote.mdx | 131 ++
.../_request-a-grant-continuation.mdx | 100 ++
.../_get-wallet-address.mdx | 60 +
.../_grant-request-outgoing-payment.mdx | 231 +++
.../_request-a-grant-continuation.mdx | 101 ++
.../_create-incoming-payment-open.mdx | 103 ++
.../_create-outgoing-payment.mdx | 133 ++
.../_get-wallet-address.mdx | 75 +
.../_grant-request-incoming-payment.mdx | 125 ++
.../_grant-request-outgoing-payment.mdx | 241 +++
.../_request-a-grant-continuation.mdx | 103 ++
.../_create-incoming-payment.mdx | 103 ++
.../_create-outgoing-payment.mdx | 111 ++
.../_create-quote-ilp.mdx | 134 ++
.../_get-wallet-address.mdx | 75 +
.../_grant-request-incoming-payment.mdx | 124 ++
.../_grant-request-outgoing-payment.mdx | 241 +++
.../_grant-request-quote.mdx | 124 ++
.../_request-a-grant-continuation.mdx | 103 ++
.../_create-incoming-payment.mdx | 123 ++
.../_create-outgoing-payment.mdx | 109 ++
.../_create-quote.mdx | 111 ++
.../_get-wallet-address.mdx | 75 +
.../_grant-request-incoming-payment.mdx | 124 ++
.../_grant-request-outgoing-payment.mdx | 246 +++
.../_grant-request-quote.mdx | 127 ++
.../_request-a-grant-continuation.mdx | 100 ++
.../_create-incoming-payments.mdx | 198 +++
.../_create-outgoing-payments.mdx | 183 +++
.../guides/split-payments/_create-quotes.mdx | 187 +++
.../split-payments/_get-wallet-address.mdx | 90 ++
.../_grant-request-incoming-payments.mdx | 200 +++
.../_grant-request-outgoing-payment.mdx | 253 ++++
.../split-payments/_grant-request-quote.mdx | 127 ++
.../_request-a-grant-continuation.mdx | 93 ++
73 files changed, 7886 insertions(+), 13622 deletions(-)
create mode 100644 docs/src/content/docs/partials/code/guides/accept-otp-online-purchase/_create-incoming-payment.mdx
create mode 100644 docs/src/content/docs/partials/code/guides/accept-otp-online-purchase/_create-outgoing-payment.mdx
create mode 100644 docs/src/content/docs/partials/code/guides/accept-otp-online-purchase/_create-quote.mdx
create mode 100644 docs/src/content/docs/partials/code/guides/accept-otp-online-purchase/_get-wallet-address.mdx
create mode 100644 docs/src/content/docs/partials/code/guides/accept-otp-online-purchase/_grant-continuation-request.mdx
create mode 100644 docs/src/content/docs/partials/code/guides/accept-otp-online-purchase/_grant-request-incoming-payment.mdx
create mode 100644 docs/src/content/docs/partials/code/guides/accept-otp-online-purchase/_grant-request-outgoing-payment.mdx
create mode 100644 docs/src/content/docs/partials/code/guides/accept-otp-online-purchase/_grant-request-quote.mdx
create mode 100644 docs/src/content/docs/partials/code/guides/onetime-remittance-fixed-debit/_create-incoming-payment-open.mdx
create mode 100644 docs/src/content/docs/partials/code/guides/onetime-remittance-fixed-debit/_create-outgoing-payment.mdx
create mode 100644 docs/src/content/docs/partials/code/guides/onetime-remittance-fixed-debit/_create-quote-debit-amount.mdx
create mode 100644 docs/src/content/docs/partials/code/guides/onetime-remittance-fixed-debit/_get-wallet-address.mdx
create mode 100644 docs/src/content/docs/partials/code/guides/onetime-remittance-fixed-debit/_grant-request-incoming-payment.mdx
create mode 100644 docs/src/content/docs/partials/code/guides/onetime-remittance-fixed-debit/_grant-request-outgoing-payment.mdx
create mode 100644 docs/src/content/docs/partials/code/guides/onetime-remittance-fixed-debit/_grant-request-quote.mdx
create mode 100644 docs/src/content/docs/partials/code/guides/onetime-remittance-fixed-debit/_request-a-grant-continuation.mdx
create mode 100644 docs/src/content/docs/partials/code/guides/onetime-remittance-fixed-receive/_create-incoming-payment.mdx
create mode 100644 docs/src/content/docs/partials/code/guides/onetime-remittance-fixed-receive/_create-outgoing-payment.mdx
create mode 100644 docs/src/content/docs/partials/code/guides/onetime-remittance-fixed-receive/_create-quote-ilp.mdx
create mode 100644 docs/src/content/docs/partials/code/guides/onetime-remittance-fixed-receive/_get-wallet-address.mdx
create mode 100644 docs/src/content/docs/partials/code/guides/onetime-remittance-fixed-receive/_grant-request-incoming-payment.mdx
create mode 100644 docs/src/content/docs/partials/code/guides/onetime-remittance-fixed-receive/_grant-request-outgoing-payment.mdx
create mode 100644 docs/src/content/docs/partials/code/guides/onetime-remittance-fixed-receive/_grant-request-quote.mdx
create mode 100644 docs/src/content/docs/partials/code/guides/onetime-remittance-fixed-receive/_request-a-grant-continuation.mdx
create mode 100644 docs/src/content/docs/partials/code/guides/outgoing-grant-future-payments/_get-wallet-address.mdx
create mode 100644 docs/src/content/docs/partials/code/guides/outgoing-grant-future-payments/_grant-request-outgoing-payment.mdx
create mode 100644 docs/src/content/docs/partials/code/guides/outgoing-grant-future-payments/_request-a-grant-continuation.mdx
create mode 100644 docs/src/content/docs/partials/code/guides/recurring-remittance-fixed-debit/_create-incoming-payment-open.mdx
create mode 100644 docs/src/content/docs/partials/code/guides/recurring-remittance-fixed-debit/_create-outgoing-payment.mdx
create mode 100644 docs/src/content/docs/partials/code/guides/recurring-remittance-fixed-debit/_get-wallet-address.mdx
create mode 100644 docs/src/content/docs/partials/code/guides/recurring-remittance-fixed-debit/_grant-request-incoming-payment.mdx
create mode 100644 docs/src/content/docs/partials/code/guides/recurring-remittance-fixed-debit/_grant-request-outgoing-payment.mdx
create mode 100644 docs/src/content/docs/partials/code/guides/recurring-remittance-fixed-debit/_request-a-grant-continuation.mdx
create mode 100644 docs/src/content/docs/partials/code/guides/recurring-remittance-fixed-receive/_create-incoming-payment.mdx
create mode 100644 docs/src/content/docs/partials/code/guides/recurring-remittance-fixed-receive/_create-outgoing-payment.mdx
create mode 100644 docs/src/content/docs/partials/code/guides/recurring-remittance-fixed-receive/_create-quote-ilp.mdx
create mode 100644 docs/src/content/docs/partials/code/guides/recurring-remittance-fixed-receive/_get-wallet-address.mdx
create mode 100644 docs/src/content/docs/partials/code/guides/recurring-remittance-fixed-receive/_grant-request-incoming-payment.mdx
create mode 100644 docs/src/content/docs/partials/code/guides/recurring-remittance-fixed-receive/_grant-request-outgoing-payment.mdx
create mode 100644 docs/src/content/docs/partials/code/guides/recurring-remittance-fixed-receive/_grant-request-quote.mdx
create mode 100644 docs/src/content/docs/partials/code/guides/recurring-remittance-fixed-receive/_request-a-grant-continuation.mdx
create mode 100644 docs/src/content/docs/partials/code/guides/recurring-subscription-incoming-amount/_create-incoming-payment.mdx
create mode 100644 docs/src/content/docs/partials/code/guides/recurring-subscription-incoming-amount/_create-outgoing-payment.mdx
create mode 100644 docs/src/content/docs/partials/code/guides/recurring-subscription-incoming-amount/_create-quote.mdx
create mode 100644 docs/src/content/docs/partials/code/guides/recurring-subscription-incoming-amount/_get-wallet-address.mdx
create mode 100644 docs/src/content/docs/partials/code/guides/recurring-subscription-incoming-amount/_grant-request-incoming-payment.mdx
create mode 100644 docs/src/content/docs/partials/code/guides/recurring-subscription-incoming-amount/_grant-request-outgoing-payment.mdx
create mode 100644 docs/src/content/docs/partials/code/guides/recurring-subscription-incoming-amount/_grant-request-quote.mdx
create mode 100644 docs/src/content/docs/partials/code/guides/recurring-subscription-incoming-amount/_request-a-grant-continuation.mdx
create mode 100644 docs/src/content/docs/partials/code/guides/split-payments/_create-incoming-payments.mdx
create mode 100644 docs/src/content/docs/partials/code/guides/split-payments/_create-outgoing-payments.mdx
create mode 100644 docs/src/content/docs/partials/code/guides/split-payments/_create-quotes.mdx
create mode 100644 docs/src/content/docs/partials/code/guides/split-payments/_get-wallet-address.mdx
create mode 100644 docs/src/content/docs/partials/code/guides/split-payments/_grant-request-incoming-payments.mdx
create mode 100644 docs/src/content/docs/partials/code/guides/split-payments/_grant-request-outgoing-payment.mdx
create mode 100644 docs/src/content/docs/partials/code/guides/split-payments/_grant-request-quote.mdx
create mode 100644 docs/src/content/docs/partials/code/guides/split-payments/_request-a-grant-continuation.mdx
diff --git a/docs/src/content/docs/es/guides/accept-otp-online-purchase.mdx b/docs/src/content/docs/es/guides/accept-otp-online-purchase.mdx
index ddc068aa..b99b2606 100644
--- a/docs/src/content/docs/es/guides/accept-otp-online-purchase.mdx
+++ b/docs/src/content/docs/es/guides/accept-otp-online-purchase.mdx
@@ -6,6 +6,14 @@ import { LinkOut } from '@interledger/docs-design-system'
import { Tabs, TabItem, Badge } from '@astrojs/starlight/components'
import Start from '/src/content/docs/partials/es/_grant-start-interaction.mdx'
import Finish from '/src/content/docs/partials/es/_grant-finish-interaction.mdx'
+import GetWalletAddress from '/src/content/docs/partials/code/guides/accept-otp-online-purchase/_get-wallet-address.mdx'
+import GrantRequestIncomingPayment from '/src/content/docs/partials/code/guides/accept-otp-online-purchase/_grant-request-incoming-payment.mdx'
+import CreateIncomingPayment from '/src/content/docs/partials/code/guides/accept-otp-online-purchase/_create-incoming-payment.mdx'
+import GrantRequestQuote from '/src/content/docs/partials/code/guides/accept-otp-online-purchase/_grant-request-quote.mdx'
+import CreateQuote from '/src/content/docs/partials/code/guides/accept-otp-online-purchase/_create-quote.mdx'
+import GrantRequestOutgoingPayment from '/src/content/docs/partials/code/guides/accept-otp-online-purchase/_grant-request-outgoing-payment.mdx'
+import CreateOutgoingPayment from '/src/content/docs/partials/code/guides/accept-otp-online-purchase/_create-outgoing-payment.mdx'
+import GrantContinuationRequest from '/src/content/docs/partials/code/guides/accept-otp-online-purchase/_grant-continuation-request.mdx'
:::tip[Resumen]
Aprenda a aceptar un pago único por una cantidad previamente pactada.
@@ -63,71 +71,7 @@ Asumamos que el cliente ingresó su dirección de billetera en el formulario de
Llame a la [Get Wallet Address API](/apis/wallet-address-server/operations/get-wallet-address) para cada dirección.
-
-
-
-```ts wrap
-const customerWalletAddress = await client.walletAddress.get({
- url: 'https://cloudninebank.example.com/customer'
-})
-const retailerWalletAddress = await client.walletAddress.get({
- url: 'https://happylifebank.example.com/retailer'
-})
-```
-
-
-
-
-```rust wrap
-let sender_wallet_address = client.wallet_address().get("https://cloudninebank.example.com/customer").await?;
-let retailer_wallet_address = client.wallet_address().get("https://happylifebank.example.com/retailer").await?;
-```
-
-
-
-
-
-```php wrap
-$customerWalletAddress = $client->walletAddress()->get([
- 'url' => 'https://cloudninebank.example.com/customer'
-]);
-$retailerWalletAddress = $client->walletAddress()->get([
- 'url' => 'https://happylifebank.example.com/retailer'
-]);
-```
-
-
-
-
-
-```go wrap
-customerWalletAddress, err := client.WalletAddress.Get(context.TODO(), op.WalletAddressGetParams{
- URL: "https://cloudninebank.example.com/customer",
-})
-if err != nil {
- log.Fatalf("Error fetching customer wallet address: %v\n", err)
-}
-
-retailerWalletAddress, err := client.WalletAddress.Get(context.TODO(), op.WalletAddressGetParams{
- URL: "https://happylifebank.example.com/retailer",
-})
-if err != nil {
- log.Fatalf("Error fetching retailer wallet address: %v\n", err)
-}
-
-```
-
-
-
-
-
-```java wrap
-var customerWalletAddress = client.walletAddress().get("https://cloudninebank.example.com/customer");
-var retailerWalletAddress = client.walletAddress().get("https://happylifebank.example.com/retailer");
-```
-
-
-
+
Ejemplo de respuesta
@@ -152,107 +96,7 @@ Utilice los datos del minorista `authServer`, recibidos en el paso anterior, par
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.
-
-
-
-```ts wrap
-const retailerIncomingPaymentGrant = await client.grant.request(
- {
- url: retailerWalletAddress.authServer
- },
- {
- access_token: {
- access: [
- {
- type: 'incoming-payment',
- actions: ['create']
- }
- ]
- }
- }
-)
-```
-
-
-
-
-```rust wrap
-use open_payments::types::{AccessTokenRequest, AccessItem, IncomingPaymentAction, GrantRequest};
-
-let incoming_access = AccessTokenRequest {
-access: vec![AccessItem::IncomingPayment { actions: vec![IncomingPaymentAction::Create], identifier: None }],
-};
-let incoming_grant_request = GrantRequest::new(incoming_access, None);
-
-let retailer_incoming_payment_grant = client
-.grant()
-.request(&retailer_wallet_address.auth_server, &incoming_grant_request)
-.await?;
-
-```
-
-
-
-
-
-```php wrap
-$retailerIncomingPaymentGrant = $client->grant()->request(
- [
- 'url' => $retailerWalletAddress->authServer
- ],
- [
- 'access_token' => [
- 'access' => [
- [
- 'type' => 'incoming-payment',
- 'actions' => ['create']
- ]
- ]
- ]
- ]
-);
-```
-
-
-
-
-
-```go wrap
-incomingAccess := as.AccessIncoming{
- Type: as.IncomingPayment,
- Actions: []as.AccessIncomingActions{as.AccessIncomingActionsCreate},
-}
-accessItem := as.AccessItem{}
-if err := accessItem.FromAccessIncoming(incomingAccess); err != nil {
- log.Fatalf("Error creating AccessItem: %v\n", err)
-}
-accessToken := struct {
- Access as.Access `json:"access"`
-}{
- Access: []as.AccessItem{accessItem},
-}
-
-retailerIncomingPaymentGrant, err := client.Grant.Request(context.TODO(), op.GrantRequestParams{
- URL: *retailerWalletAddress.AuthServer,
- RequestBody: as.GrantRequestWithAccessToken{AccessToken: accessToken},
-})
-if err != nil {
- log.Fatalf("Error requesting incoming payment grant: %v\n", err)
-}
-```
-
-
-
-
-
-```java wrap
-var retailerIncomingPaymentGrant = client.auth().grant().incomingPayment(
- retailerWalletAddress
-);
-```
-
-
-
+
Ejemplo de respuesta
@@ -290,106 +134,7 @@ Esta llamada solicita la creación de un recurso de pago entrante en la cuenta d
Recuerde que el monto total de la compra del cliente es de MXN 1400.
-
-
-
-```ts wrap
-const retailerIncomingPayment = await.client.incomingPayment.create(
- {
- url: retailerWalletAddress.resourceServer,
- accessToken: retailerIncomingPaymentGrant.access_token.value
- },
- {
- walletAddress: retailerWalletAddress.id,
- incomingAmount: {
- value: '140000',
- assetCode: 'MXN',
- assetScale: 2
- }
- }
-)
-```
-
-
-
-
-```rust wrap
-use open_payments::types::{IncomingPaymentRequest, Amount};
-
-let incoming_request = IncomingPaymentRequest {
-wallet_address: retailer_wallet_address.id.clone(),
-incoming_amount: Some(Amount { value: "140000".into(), asset_code: "MXN".into(), asset_scale: 2 }),
-expires_at: None,
-metadata: None,
-};
-
-let retailer_incoming_payment = client
-.incoming_payments()
-.create(
-&retailer_wallet_address.resource_server,
-&incoming_request,
-Some(&retailer_incoming_payment_grant.access_token.value),
-)
-.await?;
-
-```
-
-
-
-
-
-```php wrap
-$retailerIncomingPayment = $client->incomingPayment()->create(
- [
- 'url' => $retailerWalletAddress->resourceServer,
- 'accessToken' => $retailerIncomingPaymentGrant->access_token->value
- ],
- [
- 'walletAddress' => $retailerWalletAddress->id,
- 'incomingAmount' => [
- 'value' => '140000',
- 'assetCode' => 'MXN',
- 'assetScale' => 2
- ]
- ]
-);
-```
-
-
-
-
-```go wrap
-incomingPayment, err := client.IncomingPayment.Create(context.TODO(), op.IncomingPaymentCreateParams{
- BaseURL: *retailerWalletAddress.ResourceServer,
- AccessToken: retailerIncomingPaymentGrant.AccessToken.Value,
- Payload: rs.CreateIncomingPaymentJSONBody{
- WalletAddressSchema: *retailerWalletAddress.Id,
- IncomingAmount: &rs.Amount{
- Value: "140000",
- AssetCode: "MXN",
- AssetScale: 2,
- },
- },
-})
-if err != nil {
- log.Fatalf("Error creating incoming payment: %v\n", err)
-}
-```
-
-
-
-
-
-```java wrap
-var retailerIncomingPayment = client.payment().createIncoming(
- retailerWalletAddress,
- retailerIncomingPaymentGrant,
- BigDecimal.valueOf(1400.00)
-);
-```
-
-
-
+
Ejemplo de respuesta
@@ -430,106 +175,7 @@ Utilice los datos del consumidor `authServer`, devueltos en el paso 1, para llam
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.
-
-
-
-```ts wrap
-const customerQuoteGrant = await client.grant.request(
- {
- url: customerWalletAddress.authServer
- },
- {
- access_token: {
- access: [
- {
- type: 'quote',
- actions: ['create']
- }
- ]
- }
- }
-)
-```
-
-
-
-
-```rust wrap
-use open_payments::types::{AccessTokenRequest, AccessItem, QuoteAction, GrantRequest};
-
-let quote_access = AccessTokenRequest {
-access: vec![AccessItem::Quote { actions: vec![QuoteAction::Create] }],
-};
-let quote_grant_request = GrantRequest::new(quote_access, None);
-let customer_quote_grant = client
-.grant()
-.request(&customer_wallet_address.auth_server, "e_grant_request)
-.await?;
-
-```
-
-
-
-
-
-```php wrap
-$customerQuoteGrant = $client->grant()->request(
- [
- 'url' => $customerWalletAddress->authServer
- ],
- [
- 'access_token' => [
- 'access' => [
- [
- 'type' => 'quote',
- 'actions' => ['create']
- ]
- ]
- ]
- ]
-);
-```
-
-
-
-
-
-```go wrap
-quoteAccess := as.AccessQuote{
- Type: as.Quote,
- Actions: []as.AccessQuoteActions{as.Create},
-}
-quoteAccessItem := as.AccessItem{}
-if err := quoteAccessItem.FromAccessQuote(quoteAccess); err != nil {
- log.Fatalf("Error creating AccessItem: %v\n", err)
-}
-quoteAccessToken := struct {
- Access as.Access `json:"access"`
-}{
- Access: []as.AccessItem{quoteAccessItem},
-}
-
-customerQuoteGrant, err := client.Grant.Request(context.TODO(), op.GrantRequestParams{
- URL: *customerWalletAddress.AuthServer,
- RequestBody: as.GrantRequestWithAccessToken{AccessToken: quoteAccessToken},
-})
-if err != nil {
- log.Fatalf("Error requesting quote grant: %v\n", err)
-}
-```
-
-
-
-
-
-```java wrap
-var customerQuoteGrant = client.auth().grant().quote(
- customerWalletAddress
-);
-```
-
-
-
+
Ejemplo de respuesta
@@ -567,106 +213,7 @@ Esta llamada solicita la creación de un recurso de cotización en la cuenta de
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.
-
-
-
-```ts wrap
-const customerQuote = await client.quote.create(
- {
- url: customerWalletAddress.resourceServer,
- accessToken: customerQuoteGrant.access_token.value
- },
- {
- method: 'ilp',
- walletAddress: customerWalletAddress.id,
- receiver: retailerIncomingPayment.id
- }
-)
-```
-
-
-
-
-```rust wrap
-use open_payments::types::{QuoteRequest, QuoteMethod};
-
-let quote_request = QuoteRequest {
-method: QuoteMethod::Ilp,
-wallet_address: Some(customer_wallet_address.id.clone()),
-receiver: Some(retailer_incoming_payment.id.clone()),
-debit_amount: None,
-receive_amount: None,
-};
-
-let customer_quote = client
-.quotes()
-.create(
-&customer_wallet_address.resource_server,
-"e_request,
-Some(&customer_quote_grant.access_token.value),
-)
-.await?;
-
-```
-
-
-
-
-
-```php wrap
-$customerQuote = $client->quote()->create(
- [
- 'url' => $customerWalletAddress->resourceServer,
- 'accessToken' => $customerQuoteGrant->access_token->value
- ],
- [
- 'method' => 'ilp',
- 'walletAddress' => $customerWalletAddress->id,
- 'receiver' => $retailerIncomingPayment->id
- ]
-);
-```
-
-
-
-
-
-```go wrap
-customerQuote, err := client.Quote.Create(context.TODO(), op.QuoteCreateParams{
- BaseURL: *customerWalletAddress.ResourceServer,
- AccessToken: customerQuoteGrant.AccessToken.Value,
- Payload: rs.CreateQuoteJSONBody0{
- WalletAddressSchema: *customerWalletAddress.Id,
- Receiver: *incomingPayment.Id,
- Method: "ilp",
- },
-})
-if err != nil {
- log.Fatalf("Error creating quote: %v\n", err)
-}
-```
-
-
-
-
-
-```java wrap
-var customerQuote = client.quote().create(
- customerQuoteGrant.getAccess().getToken(),
- customerWalletAddress,
- retailerIncomingPayment,
- Optional.empty(),
- Optional.empty()
-);
-```
-
-
-
-
-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 del `incomingAmount` del recurso de pago entrante.
+
Ejemplo de respuesta
@@ -695,6 +242,11 @@ El siguiente es un ejemplo de respuesta proveniente del proveedor de billetera d
+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 del `incomingAmount` del recurso de pago entrante.
+
### 6. Solicitar una concesión de autorización interactiva para un pago saliente
Utilice la información del consumidor `authServer` para llamar a la [Grant Request](/apis/auth-server/operations/post-request).
@@ -705,180 +257,7 @@ Esta llamada obtiene un token de acceso que permite a la aplicación cliente sol
Los pagos salientes requieren una concesión de autorización interactiva. Este tipo de concesión de autorización obtendrá el consentimiento del cliente antes de que se realice un pago saliente desde su cuenta de billetera. Puede encontrar más información en las páginas del [flujo de Open Payments](/es/concepts/op-flow/#pago-saliente) y [proveedores de identidad](/es/identity/idp).
:::
-
-
-
-```ts wrap
-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
- }
- }
- }
-)
-```
-
-
-
-
-```rust wrap
-use open_payments::types::{AccessTokenRequest, AccessItem, OutgoingPaymentAction, InteractRequest, InteractStart, InteractFinish, InteractFinishMethod, AccessLimits, Amount, GrantRequest};
-
-let access_limits = AccessLimits {
- debit_amount: Some(Amount { value: "140000".into(), asset_code: "MXN".into(), asset_scale: 2 }),
- ..Default::default()
-};
-let access_request = AccessTokenRequest {
- access: vec![AccessItem::OutgoingPayment {
- identifier: Some(customer_wallet_address.id.clone()),
- actions: vec![OutgoingPaymentAction::Create],
- limits: Some(access_limits),
- }],
-};
-let interact_request = InteractRequest {
- start: Some(vec![InteractStart::Redirect]),
- finish: Some(InteractFinish {
- method: InteractFinishMethod::Redirect,
- uri: Some("https://paymentplatform.example/finish/{...}".into()),
- nonce: Some("NONCE".into()),
- }),
-};
-
-let grant_request = GrantRequest::new(access_request, Some(interact_request));
-let pending_customer_outgoing_payment_grant = client
- .grant()
- .request(&customer_wallet_address.auth_server, &grant_request)
- .await?;
-```
-
-
-
-
-
-```php wrap
-$pendingCustomerOutgoingPaymentGrant = $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'
- ]
- ]
- ]
-);
-```
-
-
-
-
-
-```go wrap
-outgoingAccess := as.AccessOutgoing{
- Type: as.OutgoingPayment,
- Actions: []as.AccessOutgoingActions{as.AccessOutgoingActionsCreate},
- Identifier: *customerWalletAddress.Id,
- Limits: &as.LimitsOutgoing{
- DebitAmount: &as.Amount{
- Value: "140000",
- AssetCode: "MXN",
- AssetScale: 2,
- },
- },
-}
-outgoingAccessItem := as.AccessItem{}
-if err := outgoingAccessItem.FromAccessOutgoing(outgoingAccess); err != nil {
- log.Fatalf("Error creating AccessItem: %v\n", err)
-}
-outgoingAccessToken := struct {
- Access as.Access `json:"access"`
-}{
- Access: []as.AccessItem{outgoingAccessItem},
-}
-interact := &as.InteractRequest{
- Start: []as.InteractRequestStart{as.InteractRequestStartRedirect},
- Finish: &as.InteractRequestFinish{
- Method: as.Redirect,
- Uri: "https://paymentplatform.example/finish/{...}",
- Nonce: NONCE,
- },
-}
-
-pendingCustomerOutgoingPaymentGrant, err := client.Grant.Request(context.TODO(), op.GrantRequestParams{
- URL: *customerWalletAddress.AuthServer,
- RequestBody: as.GrantRequestWithAccessToken{
- AccessToken: outgoingAccessToken,
- Interact: interact,
- },
-})
-
-if err != nil {
- log.Fatalf("Error requesting outgoing payment grant: %v\n", err)
-}
-```
-
-
-
-
-
-```java wrap
-var urlToOpen = "https://paymentplatform.example/finish/{...}";
-
-var opContinueInteract = client.auth().grant().continuation(
- customerWalletAddress,
- customerQuote.getDebitAmount(),
- URI.create(urlToOpen),
- "NONCE"
-);
-```
-
-
-
-
+
Ejemplo de respuesta
@@ -925,88 +304,7 @@ Emita la solicitud al `continue.uri` proporcionado en la respuesta de concesión
Incluya la `interact_ref` devuelta en los parámetros de consulta del URI de redirección.
-
-
-
-```ts wrap
-const customerOutgoingPaymentGrant = await client.grant.continue(
- {
- url: pendingCustomerOutgoingPaymentGrant.continue.uri,
- accessToken: pendingCustomerOutgoingPaymentGrant.continue.access_token.value
- },
- {
- interact_ref: interactRef
- }
-)
-```
-
-
-
-
-```rust wrap
-let continue_field = match &pending_customer_outgoing_payment_grant.continue_field {
- Some(c) => c,
- None => {
- eprintln!("Missing continue field on pending grant");
- return Ok(());
- }
-};
-
-let customer_outgoing_payment_grant = client
-.grant()
-.continue_grant(
-&continue_field.uri,
-&interact_ref,
-Some(&continue_field.access_token.value),
-)
-.await?;
-
-```
-
-
-
-
-
-```php wrap
-$customerOutgoingPaymentGrant = $client->grant()->continue(
- [
- 'url' => $pendingCustomerOutgoingPaymentGrant->continue->uri,
- 'accessToken' => $pendingCustomerOutgoingPaymentGrant->continue->access_token->value
- ],
- [
- 'interact_ref' => $interactRef
- ]
-);
-```
-
-
-
-
-
-```go wrap
-customerOutgoingPaymentGrant, err := client.Grant.Continue(context.TODO(), op.GrantContinueParams{
- URL: pendingCustomerOutgoingPaymentGrant.Continue.Uri,
- AccessToken: pendingCustomerOutgoingPaymentGrant.Continue.AccessToken.Value,
- InteractRef: INTERACT_REF,
-})
-if err != nil {
- log.Fatalf("Error continuing grant: %v\n", err)
-}
-```
-
-
-
-
-
-```java wrap
-var customerOutgoingPaymentGrant = client.auth().grant().finalize(
- opContinueInteract,
- interactRef
-);
-```
-
-
-
+
Ejemplo de respuesta
@@ -1044,100 +342,7 @@ El siguiente es un ejemplo de respuesta proveniente del proveedor de billetera d
Utilice el token de acceso devuelto en el paso 9 para llamar a la [Create Outgoing Payment API](/apis/resource-server/operations/create-outgoing-payment/). 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).
-
-
-
-```ts wrap
-const customerOutgoingPayment = await client.outgoingPayment.create(
- {
- url: customerWalletAddress.resourceServer,
- accessToken: customerOutgoingPaymentGrant.access_token.value
- },
- {
- walletAddress: customerWalletAddress.id,
- quoteId: customerQuote.id
- }
-)
-```
-
-
-
-
-```rust wrap
-use open_payments::types::OutgoingPaymentRequest;
-let outgoing_request = OutgoingPaymentRequest {
- wallet_address: customer_wallet_address.id.clone(),
- receiver: Some(retailer_incoming_payment.id.clone()),
- debit_amount: None,
- receive_amount: None,
- quote_id: Some(customer_quote.id.clone()),
-};
-let customer_outgoing_payment_to_retailer = client
- .outgoing_payments()
- .create(
- &customer_wallet_address.resource_server,
- &outgoing_request,
- Some(&customer_outgoing_payment_grant.access_token.value),
- )
- .await?;
-```
-
-
-
-
-
-```php wrap
-$customerOutgoingPayment = $client->outgoingPayment()->create(
- [
- 'url' => $customerWalletAddress->resourceServer,
- 'accessToken' => $customerOutgoingPaymentGrant->access_token->value
- ],
- [
- 'walletAddress' => $customerWalletAddress->id,
- 'quoteId' => $customerQuote->id
- ]
-);
-```
-
-
-
-
-
-```go
-var outgoingPayload rs.CreateOutgoingPaymentRequest
-if err := outgoingPayload.FromCreateOutgoingPaymentWithQuote(rs.CreateOutgoingPaymentWithQuote{
- WalletAddressSchema: *customerWalletAddress.Id,
- QuoteId: *customerQuote.Id,
-}); err != nil {
- log.Fatalf("Error creating payload: %v\n", err)
-}
-
-customerOutgoingPayment, err := client.OutgoingPayment.Create(context.TODO(), op.OutgoingPaymentCreateParams{
- BaseURL: customerWalletAddress.ResourceServer,
- AccessToken: customerOutgoingPaymentGrant.AccessToken.Value,
- Payload: outgoingPayload
-})
-if err != nil {
- log.Fatalf("Error creating outgoing payment: %v\n", err)
-}
-```
-
-
-
-
-
-```java wrap
-var customerOutgoingPayment = client.payment().createOutgoing(
- customerOutgoingPaymentGrant,
- customerWalletAddress,
- customerQuote
-);
-```
-
-
-
-
-Si la solicitud falla debido a una cotización caducada, [solicite una nueva cotización](#5-solicitar-la-creación-de-un-recurso-de-cotización) e intente de nuevo.
+
Ejemplo de respuesta
@@ -1170,6 +375,7 @@ El siguiente es un ejemplo de respuesta proveniente del proveedor de billetera d
+Si la solicitud falla debido a una cotización caducada, [solicite una nueva cotización](#5-solicitar-la-creación-de-un-recurso-de-cotización) e intente de nuevo.
:::note[Expiración del token de acceso]
Si el token de acceso de una concesión de autorización ha expirado, llame a la [Rotate Access Token API](/apis/auth-server/operations/post-token/) y, luego, utilice el nuevo token en la solicitud correspondiente.
:::
diff --git a/docs/src/content/docs/es/guides/onetime-remittance-fixed-debit.mdx b/docs/src/content/docs/es/guides/onetime-remittance-fixed-debit.mdx
index 910268d6..08b944f9 100644
--- a/docs/src/content/docs/es/guides/onetime-remittance-fixed-debit.mdx
+++ b/docs/src/content/docs/es/guides/onetime-remittance-fixed-debit.mdx
@@ -6,6 +6,14 @@ import { LinkOut } from '@interledger/docs-design-system'
import { Tabs, TabItem, Badge } from '@astrojs/starlight/components'
import Start from '/src/content/docs/partials/es/_grant-start-interaction.mdx'
import Finish from '/src/content/docs/partials/es/_grant-finish-interaction.mdx'
+import GetWalletAddress from '/src/content/docs/partials/code/guides/onetime-remittance-fixed-debit/_get-wallet-address.mdx'
+import GrantRequestIncomingPayment from '/src/content/docs/partials/code/guides/onetime-remittance-fixed-debit/_grant-request-incoming-payment.mdx'
+import CreateIncomingPaymentOpen from '/src/content/docs/partials/code/guides/onetime-remittance-fixed-debit/_create-incoming-payment-open.mdx'
+import GrantRequestQuote from '/src/content/docs/partials/code/guides/onetime-remittance-fixed-debit/_grant-request-quote.mdx'
+import CreateQuoteDebitAmount from '/src/content/docs/partials/code/guides/onetime-remittance-fixed-debit/_create-quote-debit-amount.mdx'
+import GrantRequestOutgoingPayment from '/src/content/docs/partials/code/guides/onetime-remittance-fixed-debit/_grant-request-outgoing-payment.mdx'
+import CreateOutgoingPayment from '/src/content/docs/partials/code/guides/onetime-remittance-fixed-debit/_create-outgoing-payment.mdx'
+import RequestAGrantContinuation from '/src/content/docs/partials/code/guides/onetime-remittance-fixed-debit/_request-a-grant-continuation.mdx'
:::tip[Resumen]
Aprenda cómo enviar un pago de remesa único al debitar la cuenta del remitente por un monto específico.
@@ -72,69 +80,8 @@ Asumamos que el remitente ya ha proporcionado su propia dirección de billetera
Llame a la [Get Wallet Address API](/apis/wallet-address-server/operations/get-wallet-address) para cada dirección.
-
-
+
-```ts
-const senderWalletAddress = await client.walletAddress.get({
- url: 'https://cloudninebank.example.com/sender'
-})
-const recipientWalletAddress = await client.walletAddress.get({
- url: 'https://happylifebank.example.com/recipient'
-})
-```
-
-
-
-
-```rust wrap
-let sender_wallet_address = client.wallet_address().get("https://cloudninebank.example.com/sender").await?;
-let recipient_wallet_address = client.wallet_address().get("https://happylifebank.example.com/recipient").await?;
-```
-
-
-
-
-
-```php wrap
-$senderWalletAddress = $client->walletAddress()->get([
- 'url' => 'https://cloudninebank.example.com/sender'
-]);
-$recipientWalletAddress = $client->walletAddress()->get([
- 'url' => 'https://happylifebank.example.com/recipient'
-]);
-```
-
-
-
-
-
-```go wrap
-senderWalletAddress, err := client.WalletAddress.Get(context.TODO(), op.WalletAddressGetParams{
- URL: "https://cloudninebank.example.com/sender",
-})
-if err != nil {
- log.Fatalf("Error fetching sender wallet address: %v\n", err)
-}
-
-recipientWalletAddress, err := client.WalletAddress.Get(context.TODO(), op.WalletAddressGetParams{
- URL: "https://happylifebank.example.com/recipient",
-})
-if err != nil {
- log.Fatalf("Error fetching recipient wallet address: %v\n", err)
-}
-```
-
-
-
-
-```java wrap
-var senderWalletAddress = client.walletAddress().get("https://cloudninebank.example.com/sender");
-var recipientWalletAddress = client.walletAddress().get("https://happylifebank.example.com/recipient");
-```
-
-
-
Ejemplo de respuesta
@@ -170,99 +117,8 @@ Utilice los datos del destinatario `authServer`, recibidos en el paso anterior,
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.
-
-
-
-```ts wrap
-const recipientIncomingPaymentGrant = await client.grant.request(
- {
- url: recipientWalletAddress.authServer
- },
- {
- access_token: {
- access: [
- {
- type: 'incoming-payment',
- actions: ['create']
- }
- ]
- }
- }
-)
-```
+
-
-
-
-```rust wrap
-use open_payments::types::{AccessTokenRequest, AccessItem, IncomingPaymentAction, GrantRequest};
-let incoming_access = AccessTokenRequest {
- access: vec![AccessItem::IncomingPayment { actions: vec![IncomingPaymentAction::Create, IncomingPaymentAction::Complete], identifier: None }],
-};
-let incoming_grant_request = GrantRequest::new(incoming_access, None);
-let recipient_incoming_payment_grant = client
- .grant()
- .request(&recipient_wallet_address.auth_server, &incoming_grant_request)
- .await?;
-```
-
-
-
-
-
-```php wrap
-$recipientIncomingPaymentGrant = $client->grant()->request([
- 'url' => $recipientWalletAddress->authServer
-], [
- 'access_token' => [
- 'access' => [
- [
- 'type' => 'incoming-payment',
- 'actions' => ['create']
- ]
- ]
- ]
-]);
-```
-
-
-
-
-
-```go wrap
-incomingAccess := as.AccessIncoming{
- Type: as.IncomingPayment,
- Actions: []as.AccessIncomingActions{as.AccessIncomingActionsCreate},
-}
-accessItem := as.AccessItem{}
-if err := accessItem.FromAccessIncoming(incomingAccess); err != nil {
- log.Fatalf("Error creating AccessItem: %v\n", err)
-}
-accessToken := struct {
- Access as.Access `json:"access"`
-}{
- Access: []as.AccessItem{accessItem},
-}
-
-recipientIncomingPaymentGrant, err := client.Grant.Request(context.TODO(), op.GrantRequestParams{
- URL: *recipientWalletAddress.AuthServer,
- RequestBody: as.GrantRequestWithAccessToken{AccessToken: accessToken},
-})
-if err != nil {
- log.Fatalf("Error requesting incoming payment grant: %v\n", err)
-}
-
-```
-
-
-
-
-```java wrap
-var recipientIncomingPaymentGrant = client.auth().grant().incomingPayment(recipientWalletAddress);
-```
-
-
-
Ejemplo de respuesta
El siguiente ejemplo muestra una respuesta del proveedor de billetera del destinatario.
@@ -296,85 +152,8 @@ Use el token de acceso devuelto en la respuesta anterior para llamar a la
-
+
-```ts wrap
-const recipientIncomingPayment = await client.incomingPayment.create(
- {
- url: recipientWalletAddress.resourceServer,
- accessToken: recipientIncomingPaymentGrant.access_token.value
- },
- {
- walletAddress: recipientWalletAddress.id
- }
-)
-```
-
-
-
-
-```rust wrap
-use open_payments::types::IncomingPaymentRequest;
-let incoming_request = IncomingPaymentRequest {
- wallet_address: recipient_wallet_address.id.clone(),
- incoming_amount: None,
- expires_at: None,
- metadata: None,
-};
-let recipient_incoming_payment = client
- .incoming_payments()
- .create(
- &recipient_wallet_address.resource_server,
- &incoming_request,
- Some(&recipient_incoming_payment_grant.access_token.value),
- )
- .await?;
-```
-
-
-
-
-
-```php wrap
-$recipientIncomingPayment = $client->incomingPayment()->create([
- 'url' => $recipientWalletAddress->resourceServer,
- 'accessToken' => $recipientIncomingPaymentGrant->access_token->value
-], [
- 'walletAddress' => $recipientWalletAddress->id
-]);
-```
-
-
-
-
-
-```go wrap
-recipientIncomingPayment, err := client.IncomingPayment.Create(context.TODO(), op.IncomingPaymentCreateParams{
- BaseURL: *recipientWalletAddress.ResourceServer,
- AccessToken: recipientIncomingPaymentGrant.AccessToken.Value,
- Payload: rs.CreateIncomingPaymentJSONBody{
- WalletAddressSchema: *recipientWalletAddress.Id,
- },
-})
-if err != nil {
- log.Fatalf("Error creating incoming payment: %v\n", err)
-}
-```
-
-
-
-
-```java wrap
-var recipientIncomingPayment = client.payment().createIncoming(
- recipientWalletAddress,
- recipientIncomingPaymentGrant,
- BigDecimal.valueOf(1700.00)
-);
-```
-
-
-
Ejemplo de respuesta
@@ -409,102 +188,8 @@ Utilice los datos del remitente `authServer` recibidos en el paso 1 para llamar
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.
-
-
-
- ```ts wrap
- const senderQuoteGrant = await client.grant.request(
- {
- url: senderWalletAddress.authServer
- },
- {
- access_token: {
- access: [
- {
- type: 'quote',
- actions: ['create']
- }
- ]
- }
- }
- )
- ```
-
-
-
-
-```rust wrap
-use open_payments::types::{AccessTokenRequest, AccessItem, QuoteAction, GrantRequest};
-let quote_access = AccessTokenRequest {
- access: vec![AccessItem::Quote { actions: vec![QuoteAction::Create] }],
-};
-let quote_grant_request = GrantRequest::new(quote_access, None);
-let sender_quote_grant = client
- .grant()
- .request(&sender_wallet_address.auth_server, "e_grant_request)
- .await?;
-```
-
-
-
-
-
-```php wrap
-$senderQuoteGrant = $client->grant()->request(
- [
- 'url' => $senderWalletAddress->authServer
- ],
- [
- 'access_token' => [
- 'access' => [
- [
- 'type' => 'quote',
- 'actions' => ['create']
- ]
- ]
- ]
- ]
-);
-```
-
-
-
-
-
-```go wrap
-quoteAccess := as.AccessQuote{
- Type: as.Quote,
- Actions: []as.AccessQuoteActions{as.Create},
-}
-quoteAccessItem := as.AccessItem{}
-if err := quoteAccessItem.FromAccessQuote(quoteAccess); err != nil {
- log.Fatalf("Error creating AccessItem: %v\n", err)
-}
-quoteAccessToken := struct {
- Access as.Access `json:"access"`
-}{
- Access: []as.AccessItem{quoteAccessItem},
-}
-
-senderQuoteGrant, err := client.Grant.Request(context.TODO(), op.GrantRequestParams{
- URL: senderWalletAddress.AuthServer,
- RequestBody: as.GrantRequestWithAccessToken{AccessToken: quoteAccessToken},
-})
-if err != nil {
- log.Fatalf("Error requesting quote grant: %v\n", err)
-}
-
-```
-
-
-
-
-```java wrap
-var senderQuoteGrant = client.auth().grant().quote(senderWalletAddress);
-```
+
-
-
Ejemplo de respuesta
@@ -539,126 +224,7 @@ Esta llamada solicita la creación de un recurso de cotización en la cuenta de
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.
-
-
-
-```ts wrap
-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
- }
- }
-)
-```
-
-
-
-
-```rust wrap
-use open_payments::types::{QuoteRequest, QuoteMethod, Amount};
-let quote_request = QuoteRequest {
- method: QuoteMethod::Ilp,
- wallet_address: Some(sender_wallet_address.id.clone()),
- receiver: Some(recipient_incoming_payment.id.clone()),
- debit_amount: Some(Amount {
- value: "10000".into(),
- asset_code: "USD".into(),
- asset_scale: 2,
- }),
- receive_amount: None,
-};
-let sender_quote = client
- .quotes()
- .create(
- &sender_wallet_address.resource_server,
- "e_request,
- Some(&sender_quote_grant.access_token.value),
- )
- .await?;
-```
-
-
-
-
-
-```php wrap
-$senderQuote = $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
- ]
- ]
-);
-```
-
-
-
-
-
-```go wrap
-senderQuote, err := client.Quote.Create(context.TODO(), op.QuoteCreateParams{
- BaseURL: *senderWalletAddress.ResourceServer,
- AccessToken: senderQuoteGrant.AccessToken.Value,
- Payload: rs.CreateQuoteJSONBody1{
- WalletAddressSchema: *senderWalletAddress.Id,
- Receiver: *recipientIncomingPayment.Id,
- Method: "ilp",
- DebitAmount: rs.Amount{
- Value: "10000",
- AssetCode: "USD",
- AssetScale: 2,
- },
- },
-})
-if err != nil {
- log.Fatalf("Error creating quote: %v\n", err)
-}
-```
-
-
-
-
-```java wrap
-var senderQuote = client.quote().create(
- senderQuoteGrant.getAccess().getToken(),
- senderWalletAddress,
- recipientIncomingPayment,
- Optional.of(
- Amount.build(BigDecimal.valueOf(100.00), "USD", 2)
- ),
- Optional.empty()
-);
-```
-
-
-
-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.
-
-:::note[Cotizaciones con vencimiento]
-Las cotizaciones incluyen una marca de tiempo `expiresAt`. Cree el pago saliente antes de que la cotización expire. Si la creación falla porque la cotización expiró, solicite una nueva e intente otra vez.
-:::
+
Ejemplo de respuesta
@@ -688,6 +254,16 @@ El siguiente ejemplo muestra una respuesta del proveedor de billetera del remite
+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.
+
+:::note[Cotizaciones con vencimiento]
+Las cotizaciones incluyen una marca de tiempo `expiresAt`. Cree el pago saliente antes de que la cotización expire. Si la creación falla porque la cotización expiró, solicite una nueva e intente otra vez.
+:::
+
### 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 [Grant Request API](/apis/auth-server/operations/post-request).
@@ -698,196 +274,7 @@ Esta llamada obtiene un token de acceso que permite a su aplicación solicitar l
Los pagos salientes requieren una concesión de autorización interactiva. Este tipo de concesión de autorización obtendrá el consentimiento del remitente antes de que se realice un pago saliente desde su cuenta de billetera. Puede encontrar más información en las páginas del [flujo de Open Payments](/es/concepts/op-flow/#pago-saliente) y [proveedores de identidad](/es/identity/idp).
:::
-
-
-
-```ts wrap
-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
- }
- }
- }
-)
-```
-
-
-
-
-```rust wrap
-use open_payments::types::{
- AccessTokenRequest,
- AccessItem,
- OutgoingPaymentAction,
- AccessLimits,
- Amount,
- InteractRequest,
- InteractStart,
- InteractFinish,
- InteractFinishMethod,
- GrantRequest,
-};
-
-let outgoing_access = AccessTokenRequest {
-access: vec![AccessItem::OutgoingPayment {
-identifier: Some(sender_wallet_address.id.clone()),
-actions: vec![OutgoingPaymentAction::Create],
-limits: Some(AccessLimits {
-debit_amount: Some(Amount {
-value: "10000".into(),
-asset_code: "USD".into(),
-asset_scale: 2,
-}),
-..Default::default()
-}),
-}],
-};
-
-let interact = InteractRequest {
-start: Some(vec![InteractStart::Redirect]),
-finish: Some(InteractFinish {
-method: InteractFinishMethod::Redirect,
-uri: Some("https://myapp.example.com/finish/{...}".into()),
-nonce: Some("NONCE".into()),
-}),
-};
-
-let outgoing_grant_request = GrantRequest::new(outgoing_access, Some(interact));
-
-let pending_sender_outgoing_payment_grant = client
-.grant()
-.request(&sender_wallet_address.auth_server, &outgoing_grant_request)
-.await?;
-
-```
-
-
-
-
-
-```php wrap
-$pendingSenderOutgoingPaymentGrant = $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'
- ]
- ]
- ]
-);
-```
-
-
-
-
-
-```go wrap
-outgoingAccess := as.AccessOutgoing{
- Type: as.OutgoingPayment,
- Actions: []as.AccessOutgoingActions{as.AccessOutgoingActionsCreate},
- Identifier: *senderWalletAddress.Id,
- Limits: &as.LimitsOutgoing{
- DebitAmount: &as.Amount{
- Value: "10000",
- AssetCode: "USD",
- AssetScale: 2,
- },
- },
-}
-outgoingAccessItem := as.AccessItem{}
-if err := outgoingAccessItem.FromAccessOutgoing(outgoingAccess); err != nil {
- log.Fatalf("Error creating AccessItem: %v\n", err)
-}
-outgoingAccessToken := struct {
- Access as.Access `json:"access"`
-}{
- Access: []as.AccessItem{outgoingAccessItem},
-}
-interact := &as.InteractRequest{
- Start: []as.InteractRequestStart{as.InteractRequestStartRedirect},
- Finish: &as.InteractRequestFinish{
- Method: as.Redirect,
- Uri: "https://myapp.example.com/finish/{...}",
- Nonce: NONCE,
- },
-}
-
-pendingSenderOutgoingPaymentGrant, err := client.Grant.Request(context.TODO(), op.GrantRequestParams{
- URL: *senderWalletAddress.AuthServer,
- RequestBody: as.GrantRequestWithAccessToken{
- AccessToken: outgoingAccessToken,
- Interact: interact,
- },
-})
-if err != nil {
- log.Fatalf("Error requesting outgoing payment grant: %v\n", err)
-}
-```
-
-
-
-
-```java wrap
-var debitAmount = Amount.build(BigDecimal.valueOf(100.00), "USD", 2);
-var urlToOpen = "https://myapp.example.com/finish/{...}";
-
-var opContinueInteract = client.auth().grant().continuation(
-senderWalletAddress,
-debitAmount,
-URI.create(urlToOpen),
-"NONCE"
-);
-
-```
-
-
-
+
Ejemplo de respuesta
@@ -932,85 +319,8 @@ Emita la solicitud al `continue.uri` proporcionado en la respuesta de concesión
Incluya la `interact_ref` devuelta en los parámetros de consulta del URI de redirección.
-
-
-
- ```ts wrap
- const senderOutgoingPaymentGrant = await client.grant.continue(
- {
- url: pendingSenderOutgoingPaymentGrant.continue.uri,
- accessToken: pendingSenderOutgoingPaymentGrant.continue.access_token.value
- },
- {
- interact_ref: interactRef
- }
- )
- ```
-
-
-
-
-```rust wrap
-let continue_field = match &pending_sender_outgoing_payment_grant.continue_field {
- Some(c) => c,
- None => {
- eprintln!("Missing continue field on pending grant");
- return Ok(());
- }
-};
-let sender_outgoing_payment_grant = client
- .grant()
- .continue_grant(
- &continue_field.uri,
- &interact_ref,
- Some(&continue_field.access_token.value),
- )
- .await?;
-```
-
-
-
-
-
-```php wrap
-$senderOutgoingPaymentGrant = $client->grant()->continue(
- [
- 'url' => $pendingSenderOutgoingPaymentGrant->continue->uri,
- 'accessToken' => $pendingSenderOutgoingPaymentGrant->continue->access_token->value
- ],
- [
- 'interact_ref' => $interactRef
- ]
-);
-```
-
-
-
-
-
-```go wrap
-senderOutgoingPaymentGrant, err := client.Grant.Continue(context.TODO(), op.GrantContinueParams{
- URL: pendingSenderOutgoingPaymentGrant.Continue.Uri,
- AccessToken: pendingSenderOutgoingPaymentGrant.Continue.AccessToken.Value,
- InteractRef: INTERACT_REF,
-})
-if err != nil {
- log.Fatalf("Error continuing grant: %v\n", err)
-}
-```
-
-
-
-
-```java wrap
-var senderOutgoingPaymentGrant = client.auth().grant().finalize(
- opContinueInteract,
- interactRef
-);
-```
+
-
-
Ejemplo de respuesta
@@ -1045,100 +355,7 @@ var senderOutgoingPaymentGrant = client.auth().grant().finalize(
Utilice el token de acceso devuelto en el paso 9 para llamar a la [Create Outgoing Payment API](/apis/resource-server/operations/create-outgoing-payment/). Incluya el `quoteId` en la solicitud. La `quoteId` es la `id` devuelta en la respuesta de Create Quote API (paso 5).
-
-
-
-```ts wrap
-const senderOutgoingPayment = await client.outgoingPayment.create(
- {
- url: senderWalletAddress.resourceServer,
- accessToken: senderOutgoingPaymentGrant.access_token.value
- },
- {
- walletAddress: senderWalletAddress.id,
- quoteId: senderQuote.id
- }
-)
-```
-
-
-
-
-```rust wrap
-use open_payments::types::OutgoingPaymentRequest;
-let outgoing_request = OutgoingPaymentRequest {
- wallet_address: sender_wallet_address.id.clone(),
- receiver: Some(recipient_incoming_payment.id.clone()),
- debit_amount: None,
- receive_amount: None,
- quote_id: Some(sender_quote.id.clone()),
-};
-let sender_outgoing_payment = client
- .outgoing_payments()
- .create(
- &sender_wallet_address.resource_server,
- &outgoing_request,
- Some(&sender_outgoing_payment_grant.access_token.value),
- )
- .await?;
-```
-
-
-
-
-
-```php wrap
-$senderOutgoingPayment = $client->outgoingPayment()->create(
- [
- 'url' => $senderWalletAddress->resourceServer,
- 'accessToken' => $senderOutgoingPaymentGrant->access_token->value
- ],
- [
- 'walletAddress' => $senderWalletAddress->id,
- 'quoteId' => $senderQuote->id
- ]
-);
-```
-
-
-
-
-
-```go wrap
-var outgoingPayload rs.CreateOutgoingPaymentRequest
-if err := outgoingPayload.FromCreateOutgoingPaymentWithQuote(rs.CreateOutgoingPaymentWithQuote{
- WalletAddressSchema: *senderWalletAddress.Id,
- QuoteId: *senderQuote.Id,
-}); err != nil {
- log.Fatalf("Error creating payload: %v\n", err)
-}
-
-senderOutgoingPayment, err := client.OutgoingPayment.Create(context.TODO(), op.OutgoingPaymentCreateParams{
- BaseURL: senderWalletAddress.ResourceServer,
- AccessToken: senderOutgoingPaymentGrant.AccessToken.Value,
- Payload: outgoingPayload,
-})
-if err != nil {
- log.Fatalf("Error creating outgoing payment: %v\n", err)
-}
-
-```
-
-
-
-
-```java wrap
-var senderOutgoingPayment = client.payment().createOutgoing(
- senderOutgoingPaymentGrant,
- senderWalletAddress,
- senderQuote
-);
-```
-
-
-
-
-Si la solicitud falla debido a una cotización caducada, [solicite una nueva cotización](#5-solicitar-la-creación-de-un-recurso-de-cotización) e intente de nuevo.
+
Ejemplo de respuesta
@@ -1171,6 +388,7 @@ El siguiente ejemplo muestra una respuesta cuando se crea un recurso de pago sal
+Si la solicitud falla debido a una cotización caducada, [solicite una nueva cotización](#5-solicitar-la-creación-de-un-recurso-de-cotización) e intente de nuevo.
:::note[Expiración del token de acceso]
Si el token de acceso de una concesión de autorización ha expirado, llame a la [Rotate Access Token API](/apis/auth-server/operations/post-token/) y, luego, utilice el nuevo token en la solicitud correspondiente.
:::
diff --git a/docs/src/content/docs/es/guides/onetime-remittance-fixed-receive.mdx b/docs/src/content/docs/es/guides/onetime-remittance-fixed-receive.mdx
index 2c3a6c88..43dc5de6 100644
--- a/docs/src/content/docs/es/guides/onetime-remittance-fixed-receive.mdx
+++ b/docs/src/content/docs/es/guides/onetime-remittance-fixed-receive.mdx
@@ -6,6 +6,14 @@ import { LinkOut } from '@interledger/docs-design-system'
import { Tabs, TabItem, Badge } from '@astrojs/starlight/components'
import Start from '/src/content/docs/partials/es/_grant-start-interaction.mdx'
import Finish from '/src/content/docs/partials/es/_grant-finish-interaction.mdx'
+import GetWalletAddress from '/src/content/docs/partials/code/guides/onetime-remittance-fixed-receive/_get-wallet-address.mdx'
+import GrantRequestIncomingPayment from '/src/content/docs/partials/code/guides/onetime-remittance-fixed-receive/_grant-request-incoming-payment.mdx'
+import CreateIncomingPayment from '/src/content/docs/partials/code/guides/onetime-remittance-fixed-receive/_create-incoming-payment.mdx'
+import GrantRequestQuote from '/src/content/docs/partials/code/guides/onetime-remittance-fixed-receive/_grant-request-quote.mdx'
+import CreateQuoteIlp from '/src/content/docs/partials/code/guides/onetime-remittance-fixed-receive/_create-quote-ilp.mdx'
+import GrantRequestOutgoingPayment from '/src/content/docs/partials/code/guides/onetime-remittance-fixed-receive/_grant-request-outgoing-payment.mdx'
+import CreateOutgoingPayment from '/src/content/docs/partials/code/guides/onetime-remittance-fixed-receive/_create-outgoing-payment.mdx'
+import RequestAGrantContinuation from '/src/content/docs/partials/code/guides/onetime-remittance-fixed-receive/_request-a-grant-continuation.mdx'
:::tip[Resumen]
Aprenda cómo enviar un pago de remesa único en el que el destinatario recibirá un monto fijo.
@@ -74,69 +82,7 @@ Asumamos que el remitente ya ha proporcionado su propia dirección de billetera
Llame a la [Get Wallet Address API](/apis/wallet-address-server/operations/get-wallet-address) para cada dirección.
-
-
-
-```ts wrap
-const senderWalletAddress = await client.walletAddress.get({
- url: 'https://cloudninebank.example.com/sender'
-})
-const recipientWalletAddress = await client.walletAddress.get({
- url: 'https://happylifebank.example.com/recipient'
-})
-```
-
-
-
-
-```rust wrap
-let sender_wallet_address = client.wallet_address().get("https://cloudninebank.example.com/sender").await?;
-let recipient_wallet_address = client.wallet_address().get("https://happylifebank.example.com/recipient").await?;
-```
-
-
-
-
-
-```php wrap
-$senderWalletAddress = $client->walletAddress()->get([
- 'url' => 'https://cloudninebank.example.com/sender'
-]);
-$recipientWalletAddress = $client->walletAddress()->get([
- 'url' => 'https://happylifebank.example.com/recipient'
-]);
-```
-
-
-
-
-
-```go wrap
- senderWalletAddress, err := client.WalletAddress.Get(context.TODO(), op.WalletAddressGetParams{
- URL: "https://cloudninebank.example.com/sender",
- })
- if err != nil {
- log.Fatalf("Error fetching sender wallet address: %v\n", err)
- }
-
- recipientWalletAddress, err := client.WalletAddress.Get(context.TODO(), op.WalletAddressGetParams{
- URL: "https://happylifebank.example.com/recipient",
- })
- if err != nil {
- log.Fatalf("Error fetching recipient wallet address: %v\n", err)
- }
-```
-
-
-
-
-```java wrap
-var senderWalletAddress = client.walletAddress().get("https://cloudninebank.example.com/sender");
-var recipientWalletAddress = client.walletAddress().get("https://happylifebank.example.com/recipient");
-```
-
-
-
+
Ejemplo de respuesta
@@ -173,103 +119,7 @@ Utilice los datos del destinatario `authServer`, recibidos en el paso anterior,
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.
-
-
-
-```ts wrap
-const recipientIncomingPaymentGrant = await client.grant.request(
- {
- url: recipientWalletAddress.authServer
- },
- {
- access_token: {
- access: [
- {
- type: 'incoming-payment',
- actions: ['create']
- }
- ]
- }
- }
-)
-```
-
-
-
-
-```rust wrap
-use open_payments::types::{AccessTokenRequest, AccessItem, IncomingPaymentAction, GrantRequest};
-
-let incoming_access = AccessTokenRequest {
-access: vec![AccessItem::IncomingPayment { actions: vec![IncomingPaymentAction::Create, IncomingPaymentAction::Complete], identifier: None }],
-};
-let incoming_grant_request = GrantRequest::new(incoming_access, None);
-let recipient_incoming_payment_grant = client
-.grant()
-.request(&recipient_wallet_address.auth_server, &incoming_grant_request)
-.await?;
-
-```
-
-
-
-
-
-```php wrap
-$recipientIncomingPaymentGrant = $client->grant()->request(
- [
- 'url' => $recipientWalletAddress->authServer
- ],
- [
- 'access_token' => [
- 'access' => [
- [
- 'type' => 'incoming-payment',
- 'actions' => ['create']
- ],
- ],
- ],
- ]
-);
-```
-
-
-
-
-
-```go wrap
- incomingAccess := as.AccessIncoming{
- Type: as.IncomingPayment,
- Actions: []as.AccessIncomingActions{as.AccessIncomingActionsCreate},
- }
- accessItem := as.AccessItem{}
- if err := accessItem.FromAccessIncoming(incomingAccess); err != nil {
- log.Fatalf("Error creating AccessItem: %v\n", err)
- }
- accessToken := struct {
- Access as.Access `json:"access"`
- }{
- Access: []as.AccessItem{accessItem},
- }
-
- recipientIncomingPaymentGrant, err := client.Grant.Request(context.TODO(), op.GrantRequestParams{
- URL: *recipientWalletAddress.AuthServer,
- RequestBody: as.GrantRequestWithAccessToken{AccessToken: accessToken},
- })
- if err != nil {
- log.Fatalf("Error requesting incoming payment grant: %v\n", err)
- }
-```
-
-
-
-
-```java wrap
-var recipientIncomingPaymentGrant = client.auth().grant().incomingPayment(recipientWalletAddress);
-```
-
-
-
+
Ejemplo de respuesta
@@ -305,90 +155,7 @@ Use el token de acceso devuelto en la respuesta anterior para llamar a la
-
-
-```ts wrap
-const recipientIncomingPayment = await client.incomingPayment.create(
- {
- url: recipientWalletAddress.resourceServer,
- accessToken: recipientIncomingPaymentGrant.access_token.value
- },
- {
- walletAddress: recipientWalletAddress.id
- }
-)
-```
-
-
-
-
-```rust wrap
-use open_payments::types::IncomingPaymentRequest;
-
-let incoming_request = IncomingPaymentRequest {
-wallet_address: recipient_wallet_address.id.clone(),
-incoming_amount: None,
-expires_at: None,
-metadata: None,
-};
-let recipient_incoming_payment = client
-.incoming_payments()
-.create(
-&recipient_wallet_address.resource_server,
-&incoming_request,
-Some(&recipient_incoming_payment_grant.access_token.value),
-)
-.await?;
-
-```
-
-
-
-
-
-```php wrap
-$recipientIncomingPayment = $client->incomingPayment()->create(
- [
- 'url' => $recipientWalletAddress->resourceServer,
- 'accessToken' => $recipientIncomingPaymentGrant->access_token->value
- ],
- [
- 'walletAddress' => $recipientWalletAddress->id,
- ]
-);
-```
-
-
-
-
-
-```go wrap
- recipientIncomingPayment, err := client.IncomingPayment.Create(context.TODO(), op.IncomingPaymentCreateParams{
- BaseURL: *recipientWalletAddress.ResourceServer,
- AccessToken: recipientIncomingPaymentGrant.AccessToken.Value,
- Payload: rs.CreateIncomingPaymentJSONBody{
- WalletAddressSchema: *recipientWalletAddress.Id,
- },
- })
- if err != nil {
- log.Fatalf("Error creating incoming payment: %v\n", err)
- }
-```
-
-
-
-
-```java wrap
-var recipientIncomingPayment = client.payment().createIncoming(
- recipientWalletAddress,
- recipientIncomingPaymentGrant,
- BigDecimal.valueOf(5000.00)
-);
-```
-
-
-
+
Ejemplo de respuesta
@@ -424,107 +191,7 @@ Utilice los datos del remitente `authServer` recibidos en el paso 1 para llamar
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.
-
-
-
-```ts wrap
-const senderQuoteGrant = await client.grant.request(
- {
- url: senderWalletAddress.authServer
- },
- {
- access_token: {
- access: [
- {
- type: 'quote',
- actions: ['create']
- }
- ]
- }
- }
-)
-```
-
-
-
-
-```rust wrap
-use open_payments::types::{
- AccessTokenRequest,
- AccessItem,
- QuoteAction,
- GrantRequest,
-};
-
-let quote_access = AccessTokenRequest {
-access: vec![AccessItem::Quote { actions: vec![QuoteAction::Create] }],
-};
-let quote_grant_request = GrantRequest::new(quote_access, None);
-let sender_quote_grant = client
-.grant()
-.request(&sender_wallet_address.auth_server, "e_grant_request)
-.await?;
-
-```
-
-
-
-
-```php wrap
- $senderQuoteGrant = $client->grant()->request(
- [
- 'url' => $senderWalletAddress->authServer
- ],
- [
- 'access_token' => [
- 'access' => [
- [
- 'type' => 'quote',
- 'actions' => ['create']
- ]
- ]
- ]
- ]
- );
-```
-
-
-
-
-
-```go wrap
-quoteAccess := as.AccessQuote{
- Type: as.Quote,
- Actions: []as.AccessQuoteActions{as.Create},
-}
-quoteAccessItem := as.AccessItem{}
-if err := quoteAccessItem.FromAccessQuote(quoteAccess); err != nil {
- log.Fatalf("Error creating AccessItem: %v\n", err)
-}
-quoteAccessToken := struct {
- Access as.Access `json:"access"`
-}{
- Access: []as.AccessItem{quoteAccessItem},
-}
-
-senderQuoteGrant, err := client.Grant.Request(context.TODO(), op.GrantRequestParams{
- URL: senderWalletAddress.AuthServer,
- RequestBody: as.GrantRequestWithAccessToken{AccessToken: quoteAccessToken},
-})
-if err != nil {
- log.Fatalf("Error requesting quote grant: %v\n", err)
-}
-```
-
-
-
-
-```java wrap
-var senderQuoteGrant = client.auth().grant().quote(senderWalletAddress);
-```
-
-
-
+
Ejemplo de respuesta
@@ -562,126 +229,7 @@ Esta llamada solicita la creación de un recurso de cotización en la cuenta de
El `receiveAmount` especifica que el destinatario recibirá exactamente MXN 5000.
-
-
- ```ts wrap
- const senderQuote = await client.quote.create(
- {
- url: senderWalletAddress.resourceServer,
- accessToken: senderQuoteGrant.access_token.value
- },
- {
- method: 'ilp',
- walletAddress: senderWalletAddress.id,
- receiver: recipientIncomingPayment.id,
- receiveAmount: {
- value: '500000',
- assetCode: 'MXN',
- assetScale: 2
- }
- }
- )
-```
-
-
-
-
-```rust wrap
-use open_payments::types::{QuoteRequest, QuoteMethod, Amount};
-
-let quote_request = QuoteRequest {
-method: QuoteMethod::Ilp,
-wallet_address: Some(sender_wallet_address.id.clone()),
-receiver: Some(recipient_incoming_payment.id.clone()),
-debit_amount: None,
-receive_amount: Some(Amount { value: "500000".into(), asset_code: "MXN".into(), asset_scale: 2 }),
-};
-let sender_quote = client
-.quotes()
-.create(
-&sender_wallet_address.resource_server,
-"e_request,
-Some(&sender_quote_grant.access_token.value),
-)
-.await?;
-
-```
-
-
-
-
-
-```php wrap
-$senderQuote = $client->quote()->create(
- [
- 'url' => $senderWalletAddress->resourceServer,
- 'accessToken' => $senderQuoteGrant->access_token->value
- ],
- [
- 'method' => 'ilp',
- 'walletAddress' => $senderWalletAddress->id,
- 'receiver' => $recipientIncomingPayment->id,
- 'receiveAmount' => [
- 'value' => '500000',
- 'assetCode' => 'MXN',
- 'assetScale' => 2
- ]
- ]
-);
-```
-
-
-
-
-
-```go wrap
- senderQuote, err := client.Quote.Create(context.TODO(), op.QuoteCreateParams{
- BaseURL: *senderWalletAddress.ResourceServer,
- AccessToken: senderQuoteGrant.AccessToken.Value,
- Payload: rs.CreateQuoteJSONBody2{
- WalletAddressSchema: *senderWalletAddress.Id,
- Receiver: *recipientIncomingPayment.Id,
- Method: "ilp",
- ReceiveAmount: rs.Amount{
- Value: "500000",
- AssetCode: "MXN",
- AssetScale: 2,
- },
- },
- })
- if err != nil {
- log.Fatalf("Error creating quote: %v\n", err)
- }
-```
-
-
-
-
-```java wrap
-var senderQuote = client.quote().create(
- senderQuoteGrant.getAccess().getToken(),
- senderWalletAddress,
- recipientIncomingPayment,
- Optional.empty(),
- Optional.of(
- Amount.build(BigDecimal.valueOf(5000.00), "MXN", 2)
- )
-);
-```
-
-
-
-
-La respuesta devuelve un `receiveAmount`, un `debitAmount` y demás información requerida.
-
-- `debitAmount`: el monto que el remitente debe pagar (en USD en nuestro ejemplo) después de la conversión de moneda.
-- `receiveAmount`: el monto que el destinatario recibirá realmente (exactamente MXN 5000 en nuestro ejemplo).
-
-Usted usará este mismo `receiveAmount` en el paso siguiente al solicitar la concesión de autorización del pago saliente, de modo que el remitente autorice este monto exacto.
-
-:::note[Cotizaciones con vencimiento]
-Las cotizaciones incluyen una marca de tiempo `expiresAt`. Cree el pago saliente antes de que la cotización expire. Si la creación falla porque la cotización expiró, solicite una nueva e intente otra vez.
-:::
+
Ejemplo de respuesta
@@ -711,6 +259,17 @@ El siguiente ejemplo muestra una respuesta del proveedor de billetera del remite
+La respuesta devuelve un `receiveAmount`, un `debitAmount` y demás información requerida.
+
+- `debitAmount`: el monto que el remitente debe pagar (en USD en nuestro ejemplo) después de la conversión de moneda.
+- `receiveAmount`: el monto que el destinatario recibirá realmente (exactamente MXN 5000 en nuestro ejemplo).
+
+Usted usará este mismo `receiveAmount` en el paso siguiente al solicitar la concesión de autorización del pago saliente, de modo que el remitente autorice este monto exacto.
+
+:::note[Cotizaciones con vencimiento]
+Las cotizaciones incluyen una marca de tiempo `expiresAt`. Cree el pago saliente antes de que la cotización expire. Si la creación falla porque la cotización expiró, solicite una nueva e intente otra vez.
+:::
+
### 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 [Grant Request API](/apis/auth-server/operations/post-request).
@@ -723,187 +282,7 @@ Para asegurar que el remitente autorice el monto correcto, incluya el `receiveAm
Los pagos salientes requieren una concesión de autorización interactiva. Este tipo de concesión de autorización obtendrá el consentimiento del remitente antes de que se realice un pago saliente desde su cuenta de billetera. Puede encontrar más información en las páginas del [flujo de Open Payments](/es/concepts/op-flow/#pago-saliente) y [proveedores de identidad](/es/identity/idp).
:::
-
-
- ```ts wrap
- const pendingSenderOutgoingPaymentGrant = await client.grant.request(
- {
- url: senderWalletAddress.authServer
- },
- {
- access_token: {
- access: [
- {
- identifier: senderWalletAddress.id,
- type: 'outgoing-payment',
- actions: ['create'],
- limits: {
- receiveAmount: {
- assetCode: 'MXN',
- assetScale: 2,
- value: '500000'
- }
- }
- }
- ]
- },
- 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
- }
- }
- }
-)
- ```
-
-
-
-
-```rust wrap
-use open_payments::types::{
- AccessTokenRequest,
- AccessItem,
- OutgoingPaymentAction,
- InteractRequest,
- InteractStart,
- InteractFinish,
- InteractFinishMethod,
- AccessLimits,
- Amount,
- GrantRequest,
-};
-
-let outgoing_access = AccessTokenRequest {
-access: vec![AccessItem::OutgoingPayment {
-identifier: Some(sender_wallet_address.id.clone()),
-actions: vec![OutgoingPaymentAction::Create],
-limits: Some(AccessLimits {
-receive_amount: Some(Amount { value: "500000".into(), asset_code: "MXN".into(), asset_scale: 2 }),
-..Default::default()
-}),
-}],
-};
-let interact = InteractRequest {
-start: Some(vec![InteractStart::Redirect]),
-finish: Some(InteractFinish {
-method: InteractFinishMethod::Redirect,
-uri: Some("https://myapp.example.com/finish/{...}".into()),
-nonce: Some("NONCE".into()),
-}),
-};
-let outgoing_grant_request = GrantRequest::new(outgoing_access, Some(interact));
-let pending_sender_outgoing_payment_grant = client
-.grant()
-.request(&sender_wallet_address.auth_server, &outgoing_grant_request)
-.await?;
-
-```
-
-
-
-
-
-```php wrap
-$pendingSenderOutgoingPaymentGrant = $client->grant()->request(
- [
- 'url' => $senderWalletAddress->authServer
- ],
- [
- 'access_token' => [
- 'access' => [
- [
- 'identifier' => $senderWalletAddress->id,
- 'type' => 'outgoing-payment',
- 'actions' => ['create'],
- 'limits' => [
- 'receiveAmount' => [
- 'assetCode' => 'MXN',
- 'assetScale' => 2,
- 'value' => '500000'
- ]
- ]
- ]
- ]
- ],
- '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'
- ]
- ]
- ]
-);
-```
-
-
-
-
-
-```go wrap
- outgoingAccess := as.AccessOutgoing{
- Type: as.OutgoingPayment,
- Actions: []as.AccessOutgoingActions{as.AccessOutgoingActionsCreate},
- Identifier: *senderWalletAddress.Id,
- Limits: &as.LimitsOutgoing{
- ReceiveAmount: &as.Amount{
- Value: "500000",
- AssetCode: "MXN",
- AssetScale: 2,
- },
- },
- }
- outgoingAccessItem := as.AccessItem{}
- if err := outgoingAccessItem.FromAccessOutgoing(outgoingAccess); err != nil {
- log.Fatalf("Error creating AccessItem: %v\n", err)
- }
- outgoingAccessToken := struct {
- Access as.Access `json:"access"`
- }{
- Access: []as.AccessItem{outgoingAccessItem},
- }
- interact := &as.InteractRequest{
- Start: []as.InteractRequestStart{as.InteractRequestStartRedirect},
- Finish: &as.InteractRequestFinish{
- Method: as.Redirect,
- Uri: "https://myapp.example.com/finish/{...}",
- Nonce: NONCE,
- },
- }
-
- pendingSenderOutgoingPaymentGrant, err := client.Grant.Request(context.TODO(), op.GrantRequestParams{
- URL: *senderWalletAddress.AuthServer,
- RequestBody: as.GrantRequestWithAccessToken{
- AccessToken: outgoingAccessToken,
- Interact: interact,
- },
- })
- if err != nil {
- log.Fatalf("Error requesting outgoing payment grant: %v\n", err)
- }
-```
-
-
-
-
-```java wrap
-var urlToOpen = "https://myapp.example.com/finish/{...}";
-
-var opContinueInteract = client.auth().grant().continuation(
-senderWalletAddress,
-senderQuote.getDebitAmount(),
-URI.create(urlToOpen),
-"NONCE"
-);
-
-```
-
-
-
+
Ejemplo de respuesta
@@ -950,85 +329,7 @@ Emita la solicitud al `continue.uri` proporcionado en la respuesta de concesión
Incluya la `interact_ref` devuelta en los parámetros de consulta del URI de redirección.
-
-
-
-```ts wrap
-const senderOutgoingPaymentGrant = await client.grant.continue(
- {
- url: pendingSenderOutgoingPaymentGrant.continue.uri,
- accessToken: pendingSenderOutgoingPaymentGrant.continue.access_token.value
- },
- {
- interact_ref: interactRef
- }
-)
-```
-
-
-
-
-```rust wrap
-let continue_field = match &pending_sender_outgoing_payment_grant.continue_field {
- Some(c) => c,
- None => {
- eprintln!("Missing continue field on pending grant");
- return Ok(());
- }
-};
-let sender_outgoing_payment_grant = client
- .grant()
- .continue_grant(
- &continue_field.uri,
- &interact_ref,
- Some(&continue_field.access_token.value),
- )
- .await?;
-```
-
-
-
-
-
-```php wrap
-$senderOutgoingPaymentGrant = $client->grant()->continue(
- [
- 'url' => $pendingSenderOutgoingPaymentGrant->continue->uri,
- 'accessToken' => $pendingSenderOutgoingPaymentGrant->continue->access_token->value
- ],
- [
- 'interact_ref' => $interactRef
- ]
-);
-```
-
-
-
-
-
-```go wrap
- senderOutgoingPaymentGrant, err := client.Grant.Continue(context.TODO(), op.GrantContinueParams{
- URL: pendingSenderOutgoingPaymentGrant.Continue.Uri,
- AccessToken: pendingSenderOutgoingPaymentGrant.Continue.AccessToken.Value,
- InteractRef: INTERACT_REF,
- })
- if err != nil {
- log.Fatalf("Error continuing grant: %v\n", err)
- }
-```
-
-
-
-
-```java wrap
-var senderOutgoingPaymentGrant = client.auth().grant().finalize(
- opContinueInteract,
- interactRef
-);
-```
-
-
-
+
Ejemplo de respuesta
@@ -1066,99 +367,7 @@ El siguiente ejemplo muestra una respuesta del proveedor de billetera del remite
Utilice el token de acceso devuelto en el paso 9 para llamar a la [Create Outgoing Payment API](/apis/resource-server/operations/create-outgoing-payment/). Incluya el `quoteId` en la solicitud. La `quoteId` es la `id` devuelta en la respuesta de API Crear cotización (paso 5).
-
-
-
-```ts wrap
-const senderOutgoingPayment = await client.outgoingPayment.create(
- {
- url: senderWalletAddress.resourceServer,
- accessToken: senderOutgoingPaymentGrant.access_token.value
- },
- {
- walletAddress: senderWalletAddress.id,
- quoteId: senderQuote.id
- }
-)
-```
-
-
-
-
-```rust wrap
-use open_payments::types::OutgoingPaymentRequest;
-let outgoing_request = OutgoingPaymentRequest {
- wallet_address: sender_wallet_address.id.clone(),
- receiver: Some(recipient_incoming_payment.id.clone()),
- debit_amount: None,
- receive_amount: None,
- quote_id: Some(sender_quote.id.clone()),
-};
-let sender_outgoing_payment = client
- .outgoing_payments()
- .create(
- &sender_wallet_address.resource_server,
- &outgoing_request,
- Some(&sender_outgoing_payment_grant.access_token.value),
- )
- .await?;
-```
-
-
-
-
-
-```php wrap
-$senderOutgoingPayment = $client->outgoingPayment()->create(
- [
- 'url' => $senderWalletAddress->resourceServer,
- 'accessToken' => $senderOutgoingPaymentGrant->access_token->value
- ],
- [
- 'walletAddress' => $senderWalletAddress->id,
- 'quoteId' => $senderQuote->id
- ]
-);
-```
-
-
-
-
-
-```go wrap
-var outgoingPayload rs.CreateOutgoingPaymentRequest
-if err := outgoingPayload.FromCreateOutgoingPaymentWithQuote(rs.CreateOutgoingPaymentWithQuote{
- WalletAddressSchema: *senderWalletAddress.Id,
- QuoteId: *senderQuote.Id,
-}); err != nil {
- log.Fatalf("Error creating payload: %v\n", err)
-}
-
-senderOutgoingPayment, err := client.OutgoingPayment.Create(context.TODO(), op.OutgoingPaymentCreateParams{
- BaseURL: *senderWalletAddress.ResourceServer,
- AccessToken: senderOutgoingPaymentGrant.AccessToken.Value,
- Payload: outgoingPayload,
-})
-if err != nil {
- log.Fatalf("Error creating outgoing payment: %v\n", err)
-}
-```
-
-
-
-
-```java wrap
-var senderOutgoingPayment = client.payment().createOutgoing(
- senderOutgoingPaymentGrant,
- senderWalletAddress,
- senderQuote
-);
-```
-
-
-
-
-Si la solicitud falla debido a una cotización caducada, [solicite una nueva cotización](#5-solicitar-la-creación-de-un-recurso-de-cotización) e intente de nuevo.
+
Ejemplo de respuesta
@@ -1191,6 +400,7 @@ El siguiente ejemplo muestra una respuesta del proveedor de billetera del remite
+Si la solicitud falla debido a una cotización caducada, [solicite una nueva cotización](#5-solicitar-la-creación-de-un-recurso-de-cotización) e intente de nuevo.
:::note[Expiración del token de acceso]
Si el token de acceso de una concesión de autorización ha expirado, llame a la [Rotate Access Token API](/apis/auth-server/operations/post-token/) y, luego, utilice el nuevo token en la solicitud correspondiente.
:::
diff --git a/docs/src/content/docs/es/guides/outgoing-grant-future-payments.mdx b/docs/src/content/docs/es/guides/outgoing-grant-future-payments.mdx
index f9b40ccd..60d0120d 100644
--- a/docs/src/content/docs/es/guides/outgoing-grant-future-payments.mdx
+++ b/docs/src/content/docs/es/guides/outgoing-grant-future-payments.mdx
@@ -7,6 +7,9 @@ import { Tabs, TabItem, Badge } from '@astrojs/starlight/components'
import InteractionReq from '/src/content/docs/partials/es/_interaction-required.mdx'
import Start from '/src/content/docs/partials/es/_grant-start-interaction.mdx'
import Finish from '/src/content/docs/partials/es/_grant-finish-interaction.mdx'
+import GetWalletAddress from '/src/content/docs/partials/code/guides/outgoing-grant-future-payments/_get-wallet-address.mdx'
+import GrantRequestOutgoingPayment from '/src/content/docs/partials/code/guides/outgoing-grant-future-payments/_grant-request-outgoing-payment.mdx'
+import RequestAGrantContinuation from '/src/content/docs/partials/code/guides/outgoing-grant-future-payments/_request-a-grant-continuation.mdx'
:::tip[Resumen]
Aprenda cómo obtener una concesión de pago saliente para pagos futuros sin especificar destinatarios.
@@ -41,59 +44,7 @@ En esta guía, usted asume el rol de desarrollador de una aplicación. La guía
Supongamos que su usuario guardó su dirección de billetera en el perfil de su cuenta al configurar la aplicación. Llame a la [Get Wallet Address API](/es/apis/wallet-address-server/operations/get-wallet-address) para obtener los datos necesarios sobre la cuenta de la billetera del usuario.
-
-
-
-```ts
-const userWalletAddress = await client.walletAddress.get({
- url: 'https://cloudninebank.example.com/user'
-})
-```
-
-
-
-{/* prettier-ignore-start */}
-
-
-
-```rust wrap
-let user_wallet_address = client.wallet_address().get("https://cloudninebank.example.com/user").await?;
-```
-
-
-{/* prettier-ignore-end */}
-
-
-
-```php wrap
-$userWalletAddress = $client->walletAddress()->get([
- 'url' => 'https://cloudninebank.example.com/user'
-]);
-```
-
-
-
-
-
-```go wrap
-userWalletAddress, err := client.WalletAddress.Get(context.TODO(), op.WalletAddressGetParams{
- URL: "https://cloudninebank.example.com/user",
-})
-if err != nil {
- log.Fatalf("Error fetching user wallet address: %v\n", err)
-}
-```
-
-
-
-
-
-```java wrap
-var userWalletAddress = client.walletAddress().get("https://cloudninebank.example.com/user");
-```
-
-
-
+
Ejemplo de respuesta
@@ -116,201 +67,6 @@ Utilice la información del servidor de autorización recibida en el paso anteri
-Además de los parámetros requeridos, en la solicitud incluya lo siguiente:
-
-- Objeto `limits`
- - `debitAmount`: el monto máximo que el usuario puede enviar por intervalo. Cuando comienza el siguiente intervalo, el valor se restablece.
- - `interval`: el [intervalo de tiempo](#acerca-del-intervalo) durante el cual la concesión es válida.
-
-El usuario indica que desea realizar pagos de hasta CAD 100 por mes durante tres meses. El monto se restablece todos los meses y las partes no utilizadas no se acumulan.
-
-
-
-
-```ts
-const grant = await client.grant.request(
- {
- url: userWalletAddress.authServer,
- },
- {
- access_token: {
- access: [
- {
- identifier: userWalletAddress.id,
- type: 'outgoing-payment',
- actions: ['read', 'create'],
- limits: {
- interval: 'R3/2025-05-20T13:00:00Z/P1M'
- debitAmount: {
- assetCode: 'CAD',
- assetScale: 2,
- value: '10000',
- },
- },
- },
- ],
- },
- client: userWalletAddress.id,
- interact: {
- start: ['redirect'],
- finish: {
- method: 'redirect',
- uri: 'https://cloudninebank.example.com/finish/T8jw5Xy',
- nonce: NONCE,
- },
- },
- },
-);
-```
-
-
-
-
-```rust wrap
-use open_payments::types::{AccessTokenRequest, AccessItem, OutgoingPaymentAction, AccessLimits, Amount, InteractRequest, InteractStart, InteractFinish, InteractFinishMethod, GrantRequest};
-let outgoing_access = AccessTokenRequest {
- access: vec![AccessItem::OutgoingPayment {
- identifier: Some(user_wallet_address.id.clone()),
- actions: vec![OutgoingPaymentAction::Create, OutgoingPaymentAction::Read],
- limits: Some(AccessLimits {
- interval: Some("R3/2025-05-20T13:00:00Z/P1M".into()),
- debit_amount: Some(Amount { value: "10000".into(), asset_code: "CAD".into(), asset_scale: 2 }),
- ..Default::default()
- }),
- }],
-};
-let interact = InteractRequest { start: Some(vec![InteractStart::Redirect]), finish: Some(InteractFinish { method: InteractFinishMethod::Redirect, uri: Some("https://paymentplatform.example/finish/{...}".into()), nonce: Some("NONCE".into()) }) };
-let outgoing_grant_request = GrantRequest::new(outgoing_access, Some(interact));
-let pending_user_outgoing_payment_grant = client
- .grant()
- .request(&user_wallet_address.auth_server, &outgoing_grant_request)
- .await?;
-```
-
-
-
-
-
-```php wrap
-$grant = $client->grant()->request(
- [
- 'url' => $userWalletAddress->authServer,
- ],
- [
- 'access_token' => [
- 'access' => [
- [
- 'identifier' => $userWalletAddress->id,
- 'type' => 'outgoing-payment',
- 'actions' => ['read', 'create'],
- 'limits' => [
- 'interval' => 'R3/2025-05-20T13:00:00Z/P1M',
- 'debitAmount' => [
- 'assetCode' => 'CAD',
- 'assetScale' => 2,
- 'value' => '10000',
- ],
- ],
- ],
- ],
- ],
- 'client' => $userWalletAddress->id,
- 'interact' => [
- 'start' => ['redirect'],
- 'finish' => [
- 'method' => 'redirect',
- 'uri' => 'https://paymentplatform.example/finish/{...}', // where to redirect the user to after they've completed the interaction
- 'nonce' => NONCE,
- ],
- ],
- ],
-);
-```
-
-
-
-
-
-```go wrap
-interval := "R3/2025-05-20T13:00:00Z/P1M"
-limits := as.LimitsOutgoing{}
-if err := limits.FromLimitsOutgoing1(as.LimitsOutgoing1{
- Interval: &interval,
- DebitAmount: as.Amount{
- Value: "10000",
- AssetCode: "CAD",
- AssetScale: 2,
- },
-}); err != nil {
- log.Fatalf("Error creating limits: %v\n", err)
-}
-
-outgoingAccess := as.AccessOutgoing{
- Type: as.OutgoingPayment,
- Actions: []as.AccessOutgoingActions{as.AccessOutgoingActionsCreate, as.AccessOutgoingActionsRead},
- Identifier: *userWalletAddress.Id,
- Limits: &limits,
-}
-outgoingAccessItem := as.AccessItem{}
-if err := outgoingAccessItem.FromAccessOutgoing(outgoingAccess); err != nil {
- log.Fatalf("Error creating AccessItem: %v\n", err)
-}
-outgoingAccessToken := struct {
- Access as.Access `json:"access"`
-}{
- Access: []as.AccessItem{outgoingAccessItem},
-}
-interact := &as.InteractRequest{
- Start: []as.InteractRequestStart{as.InteractRequestStartRedirect},
- Finish: &as.InteractRequestFinish{
- Method: as.Redirect,
- Uri: "https://paymentplatform.example/finish/{...}",
- Nonce: NONCE,
- },
-}
-
-pendingUserOutgoingPaymentGrant, err := client.Grant.Request(context.TODO(), op.GrantRequestParams{
- URL: *userWalletAddress.AuthServer,
- RequestBody: as.GrantRequestWithAccessToken{
- AccessToken: outgoingAccessToken,
- Interact: interact,
- },
-})
-if err != nil {
- log.Fatalf("Error requesting outgoing payment grant: %v\n", err)
-}
-```
-
-
-
-
-
-```java wrap
-var interval = "R3/2025-05-20T13:00:00Z/P1M";
-
-var limits = LimitsOutgoing.build(
- interval,
- Amount.build(BigDecimal.valueOf(100.00), "CAD", 2)
-);
-
-var accessRequest = AccessTokenRequest.build(
- userWalletAddress.getId(),
- limits
-);
-
-var urlToOpen = "https://paymentplatform.example/finish/{...}";
-
-var grantRequest = client.auth().grant().request(
- userWalletAddress,
- accessRequest,
- URI.create(urlToOpen),
- "NONCE"
-);
-```
-
-
-
-
Ejemplo de respuesta
@@ -332,6 +88,15 @@ var grantRequest = client.auth().grant().request(
+Además de los parámetros requeridos, en la solicitud incluya lo siguiente:
+
+- Objeto `limits`
+ - `debitAmount`: el monto máximo que el usuario puede enviar por intervalo. Cuando comienza el siguiente intervalo, el valor se restablece.
+ - `interval`: el [intervalo de tiempo](#acerca-del-intervalo) durante el cual la concesión es válida.
+
+El usuario indica que desea realizar pagos de hasta CAD 100 por mes durante tres meses. El monto se restablece todos los meses y las partes no utilizadas no se acumulan.
+
+
#### Acerca del intervalo
El intervalo que se emplea en esta guía es `R3/2025-05-20T13:00:00Z/P1M`. Recuerde que el usuario desea enviar pagos de hasta CAD 100 por mes durante tres meses. El intervalo se desglosa del siguiente modo:
@@ -365,88 +130,7 @@ En una situación hipotética donde una interfaz de usuario no se encuentra disp
Agregue la `interact_ref` devuelta en los parámetros de consulta del URI de redirección.
-
-
-
-```ts wrap
-const grant = await client.grant.continue(
- {
- accessToken: CONTINUE_ACCESS_TOKEN,
- url: CONTINUE_URI
- },
- {
- interact_ref: INTERACT_REF
- }
-)
-```
-
-
-
-
-```rust wrap
-let continue_field = match &pending_user_outgoing_payment_grant.continue_field {
- Some(c) => c,
- None => {
- eprintln!("Missing continue field on pending grant");
- return Ok(());
- }
-};
-let user_outgoing_payment_grant = client
- .grant()
- .continue_grant(
- &continue_field.uri,
- &interact_ref,
- Some(&continue_field.access_token.value),
- )
- .await?;
-```
-
-
-
-
-
-```php wrap
-$userOutgoingPaymentGrant = $client->grant()->continue(
- [
- 'accessToken' => $pendingUserOutgoingPaymentGrant->continue->access_token->value,
- 'url' => $pendingUserOutgoingPaymentGrant->continue->uri,
- ],
- [
- 'interact_ref' => $interactRef,
- ],
-);
-```
-
-
-
-
-
-```go wrap
-userOutgoingPaymentGrant, err := client.Grant.Continue(context.TODO(), op.GrantContinueParams{
- URL: pendingUserOutgoingPaymentGrant.Continue.Uri,
- AccessToken: pendingUserOutgoingPaymentGrant.Continue.AccessToken.Value,
- InteractRef: INTERACT_REF,
-})
-if err != nil {
- log.Fatalf("Error continuing grant: %v\n", err)
-}
-```
-
-
-
-
-
-```java wrap
-var userOutgoingPaymentGrant = client.auth().grant().finalize(
- grantRequest,
- interactRef
-);
-```
-
-
-
-
-Una respuesta exitosa proporciona a su aplicación un token de acceso. Ahora su aplicación puede emitir solicitudes de pago saliente hacia destinatarios futuros en función de la concesión. Cada solicitud debe hacer referencia al token de acceso.
+
Ejemplo de respuesta
@@ -474,7 +158,3 @@ Una respuesta exitosa proporciona a su aplicación un token de acceso. Ahora su
```
-
-:::note[Expiración del token de acceso]
-Si una solicitud de pago saliente falla porque el token de acceso de la concesión de autorización ha expirado, puede llamar a la [Rotate Access Token API](/apis/auth-server/operations/post-token/) y, luego, utilizar el nuevo token en la solicitud de pago saliente.
-:::
diff --git a/docs/src/content/docs/es/guides/recurring-remittance-fixed-debit.mdx b/docs/src/content/docs/es/guides/recurring-remittance-fixed-debit.mdx
index b9f567ae..14f8e215 100644
--- a/docs/src/content/docs/es/guides/recurring-remittance-fixed-debit.mdx
+++ b/docs/src/content/docs/es/guides/recurring-remittance-fixed-debit.mdx
@@ -6,6 +6,12 @@ import { LinkOut } from '@interledger/docs-design-system'
import { Tabs, TabItem, Badge } from '@astrojs/starlight/components'
import Start from '/src/content/docs/partials/es/_grant-start-interaction.mdx'
import Finish from '/src/content/docs/partials/es/_grant-finish-interaction.mdx'
+import GetWalletAddress from '/src/content/docs/partials/code/guides/recurring-remittance-fixed-debit/_get-wallet-address.mdx'
+import GrantRequestIncomingPayment from '/src/content/docs/partials/code/guides/recurring-remittance-fixed-debit/_grant-request-incoming-payment.mdx'
+import CreateIncomingPaymentOpen from '/src/content/docs/partials/code/guides/recurring-remittance-fixed-debit/_create-incoming-payment-open.mdx'
+import GrantRequestOutgoingPayment from '/src/content/docs/partials/code/guides/recurring-remittance-fixed-debit/_grant-request-outgoing-payment.mdx'
+import CreateOutgoingPayment from '/src/content/docs/partials/code/guides/recurring-remittance-fixed-debit/_create-outgoing-payment.mdx'
+import RequestAGrantContinuation from '/src/content/docs/partials/code/guides/recurring-remittance-fixed-debit/_request-a-grant-continuation.mdx'
:::tip[Resumen]
Aprenda cómo enviar pagos de remesas recurrentes en los que el remitente paga un monto de débito fijo con cada pago.
@@ -72,69 +78,7 @@ Supongamos que el remitente guardó la dirección de su billetera en la configur
Llame a la [Get Wallet Address API](/apis/wallet-address-server/operations/get-wallet-address) para cada dirección.
-
-
-
-```ts wrap
-const senderWalletAddress = await client.walletAddress.get({
- url: 'https://cloudninebank.example.com/sender'
-})
-const recipientWalletAddress = await client.walletAddress.get({
- url: 'https://happylifebank.example.com/recipient'
-})
-```
-
-
-
-
-```rust wrap
-let sender_wallet_address = client.wallet_address().get("https://cloudninebank.example.com/sender").await?;
-let recipient_wallet_address = client.wallet_address().get("https://happylifebank.example.com/recipient").await?;
-```
-
-
-
-
-```php wrap
-$senderWalletAddress = $client->walletAddress()->get([
- 'url' => 'https://cloudninebank.example.com/sender'
-]);
-$recipientWalletAddress = $client->walletAddress()->get([
- 'url' => 'https://happylifebank.example.com/recipient'
-]);
-```
-
-
-
-
-
-```go wrap
-senderWalletAddress, err := client.WalletAddress.Get(context.TODO(), op.WalletAddressGetParams{
- URL: "https://cloudninebank.example.com/sender",
-})
-if err != nil {
- log.Fatalf("Error fetching sender wallet address: %v\n", err)
-}
-
-recipientWalletAddress, err := client.WalletAddress.Get(context.TODO(), op.WalletAddressGetParams{
- URL: "https://happylifebank.example.com/recipient",
-})
-if err != nil {
- log.Fatalf("Error fetching recipient wallet address: %v\n", err)
-}
-```
-
-
-
-
-
-```java wrap
-var senderWalletAddress = client.walletAddress().get("https://cloudninebank.example.com/sender");
-var recipientWalletAddress = client.walletAddress().get("https://happylifebank.example.com/recipient");
-```
-
-
-
+
Ejemplo de respuesta
@@ -171,103 +115,7 @@ Utilice los datos del destinatario `authServer` recibidos en el paso 1 para llam
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.
-
-
-
-```ts wrap
-const recipientIncomingPaymentGrant = await client.grant.request(
- {
- url: recipientWalletAddress.authServer
- },
- {
- access_token: {
- access: [
- {
- type: 'incoming-payment',
- actions: ['create']
- }
- ]
- }
- }
-)
-```
-
-
-
-
-```rust wrap
-use open_payments::types::{AccessTokenRequest, AccessItem, IncomingPaymentAction, GrantRequest};
-let incoming_access = AccessTokenRequest {
- access: vec![AccessItem::IncomingPayment { actions: vec![IncomingPaymentAction::Create], identifier: None }],
-};
-let incoming_grant_request = GrantRequest::new(incoming_access, None);
-let recipient_incoming_payment_grant = client
- .grant()
- .request(&recipient_wallet_address.auth_server, &incoming_grant_request)
- .await?;
-```
-
-
-
-
-
-```php wrap
-$recipientIncomingPaymentGrant = $client->grant()->request(
- [
- 'url' => $recipientWalletAddress->authServer
- ],
- [
- 'access_token' => [
- 'access' => [
- [
- 'type' => 'incoming-payment',
- 'actions' => ['create'],
- ],
- ],
- ],
- ]
-);
-```
-
-
-
-
-
-```go
-incomingAccess := as.AccessIncoming{
- Type: as.IncomingPayment,
- Actions: []as.AccessIncomingActions{as.AccessIncomingActionsCreate},
-}
-accessItem := as.AccessItem{}
-if err := accessItem.FromAccessIncoming(incomingAccess); err != nil {
- log.Fatalf("Error creating AccessItem: %v\n", err)
-}
-accessToken := struct {
- Access as.Access `json:"access"`
-}{
- Access: []as.AccessItem{accessItem},
-}
-
-recipientIncomingPaymentGrant, err := client.Grant.Request(context.TODO(), op.GrantRequestParams{
- URL: *recipientWalletAddress.AuthServer,
- RequestBody: as.GrantRequestWithAccessToken{AccessToken: accessToken},
-})
-if err != nil {
- log.Fatalf("Error requesting incoming payment grant: %v\n", err)
-}
-```
-
-
-
-
-
-```java wrap
-var recipientIncomingPaymentGrant = client.auth().grant().incomingPayment(recipientWalletAddress);
-```
-
-
-
-
+
Ejemplo de respuesta
@@ -303,89 +151,7 @@ Use el token de acceso devuelto en la respuesta anterior para llamar a la
-
-
-```ts wrap
-const recipientIncomingPayment = await client.incomingPayment.create(
- {
- url: recipientWalletAddress.resourceServer,
- accessToken: recipientIncomingPaymentGrant.access_token.value
- },
- {
- walletAddress: recipientWalletAddress.id
- }
-)
-```
-
-
-
-
-```rust wrap
-use open_payments::types::IncomingPaymentRequest;
-let incoming_request = IncomingPaymentRequest {
- wallet_address: recipient_wallet_address.id.clone(),
- incoming_amount: None,
- expires_at: None,
- metadata: None,
-};
-let recipient_incoming_payment = client
- .incoming_payments()
- .create(
- &recipient_wallet_address.resource_server,
- &incoming_request,
- Some(&recipient_incoming_payment_grant.access_token.value),
- )
- .await?;
-```
-
-
-
-
-
-```php wrap
-$recipientIncomingPayment = $client->incomingPayment()->create(
- [
- 'url' => $recipientWalletAddress->resourceServer,
- 'accessToken' => $recipientIncomingPaymentGrant->access_token->value
- ],
- [
- 'walletAddress' => $recipientWalletAddress->id
- ]
-);
-```
-
-
-
-
-
-```go wrap
-recipientIncomingPayment, err := client.IncomingPayment.Create(context.TODO(), op.IncomingPaymentCreateParams{
- BaseURL: *recipientWalletAddress.ResourceServer,
- AccessToken: recipientIncomingPaymentGrant.AccessToken.Value,
- Payload: rs.CreateIncomingPaymentJSONBody{
- WalletAddressSchema: *recipientWalletAddress.Id,
- },
-})
-if err != nil {
- log.Fatalf("Error creating incoming payment: %v\n", err)
-}
-```
-
-
-
-
-
-```java wrap
-var recipientIncomingPayment = client.payment().createIncoming(
- recipientWalletAddress,
- recipientIncomingPaymentGrant
-);
-```
-
-
-
-
+
Ejemplo de respuesta
@@ -430,201 +196,7 @@ Como el remitente pagará un monto fijo de USD 200 al mes, la solicitud debe ten
Los pagos salientes requieren una concesión de autorización interactiva, que el remitente aprueba una sola vez. Mientras la concesión de autorización (y su token de acceso) sean válidos y estén dentro de sus límites (`interval` + `debitAmount`), su aplicación puede crear pagos salientes sin volver a aprobar cada intervalo. Puede encontrar más información en las páginas del [flujo de Open Payments](/es/concepts/op-flow/#pago-saliente) y [proveedores de identidad](/es/identity/idp).
:::
-
-
- ```ts wrap
- const pendingSenderOutgoingPaymentGrant = await client.grant.request(
- {
- url: senderWalletAddress.authServer
- },
- {
- access_token: {
- access: [
- {
- identifier: senderWalletAddress.id,
- type: 'outgoing-payment',
- actions: ['create'],
- limits: {
- interval: 'R3/2025-10-03T23:25:00Z/P1M',
- debitAmount: {
- assetCode: 'USD',
- assetScale: 2,
- value: '20000', // $200.00 USD per interval
- }
- }
- }
- ]
- },
- 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
- }
- }
- }
- )
- ```
-
-
-
-
-```rust wrap
-use open_payments::types::{
- AccessTokenRequest,
- AccessItem,
- OutgoingPaymentAction,
- LimitsOutgoing,
- Amount,
- Interval,
- InteractRequest,
- InteractFinish,
- GrantRequest,
-};
-use uuid::Uuid;
-
-let outgoing_access = AccessTokenRequest {
-access: vec![AccessItem::OutgoingPayment {
-identifier: sender_wallet_address.id.clone(),
-actions: vec![OutgoingPaymentAction::Create],
-limits: Some(LimitsOutgoing {
-receiver: None,
-debit_amount: Some(Amount {
-value: "20000".into(),
-asset_code: "USD".into(),
-asset_scale: 2,
-}),
-receive_amount: None,
-interval: Some(Interval("R3/2025-10-03T23:25:00Z/P1M".to_string())),
-}),
-}],
-};
-
-let interact = InteractRequest {
-start: vec!["redirect".to_string()],
-finish: Some(InteractFinish {
-method: "redirect".to_string(),
-uri: "https://myapp.example.com/finish/{...}".to_string(),
-nonce: Uuid::new_v4().to_string(),
-}),
-};
-
-let outgoing_grant_request = GrantRequest::new(outgoing_access, Some(interact));
-
-let pending_sender_outgoing_payment_grant = client
-.grant()
-.request(&sender_wallet_address.auth_server, &outgoing_grant_request)
-.await?;
-
-```
-
-
-
-
-
-```php wrap
-$pendingSenderOutgoingPaymentGrant = $client->grant()->request(
- [
- 'url' => $senderWalletAddress->authServer
- ],
- [
- 'access_token' => [
- 'access' => [
- [
- 'identifier' => $senderWalletAddress->id,
- 'type' => 'outgoing-payment',
- 'actions' => ['create'],
- 'limits' => [
- 'interval' => 'R3/2025-10-03T23:25:00Z/P1M',
- 'debitAmount' => [
- 'assetCode' => 'USD',
- 'assetScale' => 2,
- 'value' => '20000', // $200.00 USD per interval
- ]
- ]
- ]
- ]
- ],
- '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
- ]
- ]
- ]
-);
-```
-
-
-
-
-
-```go wrap
-interval := "R3/2025-10-03T23:25:00Z/P1M"
-limits := as.LimitsOutgoing{}
-if err := limits.FromLimitsOutgoing1(as.LimitsOutgoing1{
- Interval: &interval,
- DebitAmount: as.Amount{
- Value: "20000", // $200.00 USD per interval
- AssetCode: "USD",
- AssetScale: 2,
- },
-}); err != nil {
- log.Fatalf("Error creating limits: %v\n", err)
-}
-
-outgoingAccess := as.AccessOutgoing{
- Type: as.OutgoingPayment,
- Actions: []as.AccessOutgoingActions{as.AccessOutgoingActionsCreate},
- Identifier: *senderWalletAddress.Id,
- Limits: &limits,
-}
-outgoingAccessItem := as.AccessItem{}
-if err := outgoingAccessItem.FromAccessOutgoing(outgoingAccess); err != nil {
- log.Fatalf("Error creating AccessItem: %v\n", err)
-}
-outgoingAccessToken := struct {
- Access as.Access `json:"access"`
-}{
- Access: []as.AccessItem{outgoingAccessItem},
-}
-interact := &as.InteractRequest{
- Start: []as.InteractRequestStart{as.InteractRequestStartRedirect},
- Finish: &as.InteractRequestFinish{
- Method: as.Redirect,
- Uri: "https://myapp.example.com/finish/{...}", // where to redirect your user after they've completed the interaction
- Nonce: NONCE,
- },
-}
-
-pendingSenderOutgoingPaymentGrant, err := client.Grant.Request(context.TODO(), op.GrantRequestParams{
- URL: *senderWalletAddress.AuthServer,
- RequestBody: as.GrantRequestWithAccessToken{
- AccessToken: outgoingAccessToken,
- Interact: interact,
- },
-})
-if err != nil {
- log.Fatalf("Error requesting outgoing payment grant: %v\n", err)
-}
-```
-
-
-
-
-
-```java wrap
-// Create an outgoing payment grant with a fixed debit amount and interval using the Java SDK types.
-// See the Java SDK docs for constructing a LimitsOutgoing object with debitAmount and interval.
-var pendingSenderOutgoingPaymentGrant = client.auth().grant().outgoingPayment(senderWalletAddress);
-```
-
-
-
-
+
Ejemplo de respuesta
@@ -686,89 +258,7 @@ Emita la solicitud al `continue.uri` proporcionado en la respuesta de concesión
Incluya la `interact_ref` devuelta en los parámetros de consulta del URI de redirección.
-
-
-
-```ts wrap
-const senderOutgoingPaymentGrant = await client.grant.continue(
- {
- url: pendingSenderOutgoingPaymentGrant.continue.uri,
- accessToken: pendingSenderOutgoingPaymentGrant.continue.access_token.value
- },
- {
- interact_ref: interactRef
- }
-)
-```
-
-
-
-
-```rust wrap
-use open_payments::types::GrantResponse;
-let (continue_uri, continue_token) = match &pending_sender_outgoing_payment_grant {
- GrantResponse::WithInteraction { continue_, .. } | GrantResponse::WithToken { continue_, .. } => {
- (&continue_.uri, &continue_.access_token.value)
- }
-};
-let sender_outgoing_payment_grant = client
- .grant()
- .continue_grant(
- continue_uri,
- &interact_ref,
- Some(continue_token),
- )
- .await?;
-```
-
-
-
-
-
-```php wrap
-$senderOutgoingPaymentGrant = $client->grant()->continue(
- [
- 'url' => $pendingSenderOutgoingPaymentGrant->continue->uri,
- 'accessToken' => $pendingSenderOutgoingPaymentGrant->continue->access_token->value
- ],
- [
- 'interact_ref' => $interactRef
- ]
-);
-```
-
-
-
-
-
-```go wrap
-senderOutgoingPaymentGrant, err := client.Grant.Continue(context.TODO(), op.GrantContinueParams{
- URL: pendingSenderOutgoingPaymentGrant.Continue.Uri,
- AccessToken: pendingSenderOutgoingPaymentGrant.Continue.AccessToken.Value,
- InteractRef: INTERACT_REF,
-})
-if err != nil {
- log.Fatalf("Error continuing grant: %v\n", err)
-}
-```
-
-
-
-
-
-```java wrap
-var senderOutgoingPaymentGrant = client.grant().continueRequest(
- GrantContinueOptions.builder()
- .url(pendingSenderOutgoingPaymentGrant.getContinue().getUri())
- .accessToken(pendingSenderOutgoingPaymentGrant.getContinue().getAccessToken().getValue())
- .interactRef(interactRef)
- .build()
-);
-```
-
-
-
-
+
Ejemplo de respuesta
@@ -811,117 +301,7 @@ El siguiente ejemplo muestra una respuesta del proveedor de billetera del remite
Utilice el token de acceso devuelto en la continuación de la concesión de autorización de pago saliente (paso 7) para llamar a la [Create Outgoing Payment API](/apis/resource-server/operations/create-outgoing-payment/). Cree este pago haciendo referencia a la nueva URL `incomingPayment` y al `debitAmount` fijo.
-
-
-
-```ts wrap
-const senderOutgoingPayment = await client.outgoingPayment.create(
- {
- url: senderWalletAddress.resourceServer,
- accessToken: senderOutgoingPaymentGrant.access_token.value
- },
- {
- walletAddress: senderWalletAddress.id,
- incomingPayment: recipientIncomingPayment.id,
- debitAmount: {
- assetCode: 'USD',
- assetScale: 2,
- value: '20000'
- }
- }
-)
-```
-
-
-
-
-```rust wrap
-use open_payments::types::{OutgoingPaymentRequest, Amount};
-let outgoing_request = OutgoingPaymentRequest::FromIncomingPayment {
- wallet_address: sender_wallet_address.id.clone(),
- incoming_payment_id: recipient_incoming_payment.id.clone(),
- debit_amount: Amount {
- value: "20000".into(),
- asset_code: "USD".into(),
- asset_scale: 2,
- },
- metadata: None,
-};
-let sender_outgoing_payment = client
- .outgoing_payments()
- .create(
- &sender_wallet_address.resource_server,
- &outgoing_request,
- Some(&sender_outgoing_payment_grant.access_token.value),
- )
- .await?;
-```
-
-
-
-
-
-```php wrap
-$senderOutgoingPayment = $client->outgoingPayment()->create(
- [
- 'url' => $senderWalletAddress->resourceServer,
- 'accessToken' => $senderOutgoingPaymentGrant->access_token->value
- ],
- [
- 'walletAddress' => $senderWalletAddress->id,
- 'incomingPayment' => $recipientIncomingPayment->id,
- 'debitAmount' => [
- 'assetCode' => 'USD',
- 'assetScale' => 2,
- 'value' => '20000'
- ],
- ]
-);
-```
-
-
-
-
-
-```go wrap
-var outgoingPayload rs.CreateOutgoingPaymentRequest
-if err := outgoingPayload.FromCreateOutgoingPaymentWithoutQuote(rs.CreateOutgoingPaymentWithoutQuote{
- WalletAddressSchema: *senderWalletAddress.Id,
- IncomingPayment: *recipientIncomingPayment.Id,
- DebitAmount: &rs.Amount{
- Value: "20000",
- AssetCode: "USD",
- AssetScale: 2,
- },
-}); err != nil {
- log.Fatalf("Error creating payload: %v\n", err)
-}
-
-senderOutgoingPayment, err := client.OutgoingPayment.Create(context.TODO(), op.OutgoingPaymentCreateParams{
- BaseURL: *senderWalletAddress.ResourceServer,
- AccessToken: senderOutgoingPaymentGrant.AccessToken.Value,
- Payload: outgoingPayload,
-})
-if err != nil {
- log.Fatalf("Error creating outgoing payment: %v\n", err)
-}
-```
-
-
-
-
-
-```java wrap
-var senderOutgoingPayment = client.payment().createOutgoingFromIncoming(
- senderWalletAddress,
- recipientIncomingPayment,
- senderOutgoingPaymentGrant
-);
-```
-
-
-
-
+
Ejemplo de respuesta
diff --git a/docs/src/content/docs/es/guides/recurring-remittance-fixed-receive.mdx b/docs/src/content/docs/es/guides/recurring-remittance-fixed-receive.mdx
index fd58918c..3ad433be 100644
--- a/docs/src/content/docs/es/guides/recurring-remittance-fixed-receive.mdx
+++ b/docs/src/content/docs/es/guides/recurring-remittance-fixed-receive.mdx
@@ -6,6 +6,14 @@ import { LinkOut } from '@interledger/docs-design-system'
import { Tabs, TabItem, Badge } from '@astrojs/starlight/components'
import Start from '/src/content/docs/partials/es/_grant-start-interaction.mdx'
import Finish from '/src/content/docs/partials/es/_grant-finish-interaction.mdx'
+import GetWalletAddress from '/src/content/docs/partials/code/guides/recurring-remittance-fixed-receive/_get-wallet-address.mdx'
+import GrantRequestIncomingPayment from '/src/content/docs/partials/code/guides/recurring-remittance-fixed-receive/_grant-request-incoming-payment.mdx'
+import CreateIncomingPayment from '/src/content/docs/partials/code/guides/recurring-remittance-fixed-receive/_create-incoming-payment.mdx'
+import GrantRequestQuote from '/src/content/docs/partials/code/guides/recurring-remittance-fixed-receive/_grant-request-quote.mdx'
+import CreateQuoteIlp from '/src/content/docs/partials/code/guides/recurring-remittance-fixed-receive/_create-quote-ilp.mdx'
+import GrantRequestOutgoingPayment from '/src/content/docs/partials/code/guides/recurring-remittance-fixed-receive/_grant-request-outgoing-payment.mdx'
+import CreateOutgoingPayment from '/src/content/docs/partials/code/guides/recurring-remittance-fixed-receive/_create-outgoing-payment.mdx'
+import RequestAGrantContinuation from '/src/content/docs/partials/code/guides/recurring-remittance-fixed-receive/_request-a-grant-continuation.mdx'
:::tip[Resumen]
Aprenda cómo enviar pagos de remesa recurrentes en los que el destinatario recibirá un monto fijo en cada pago.
@@ -76,69 +84,7 @@ Supongamos que el remitente guardó la dirección de su billetera en la configur
Llame a la [Get Wallet Address API](/apis/wallet-address-server/operations/get-wallet-address) para cada dirección.
-
-
-
-```ts wrap
-const senderWalletAddress = await client.walletAddress.get({
- url: 'https://cloudninebank.example.com/sender'
-})
-const recipientWalletAddress = await client.walletAddress.get({
- url: 'https://happylifebank.example.com/recipient'
-})
-```
-
-
-
-
-```rust wrap
-let sender_wallet_address = client.wallet_address().get("https://cloudninebank.example.com/sender").await?;
-let recipient_wallet_address = client.wallet_address().get("https://happylifebank.example.com/recipient").await?;
-```
-
-
-
-
-```php wrap
-$senderWalletAddress = $client->walletAddress()->get([
- 'url' => 'https://cloudninebank.example.com/sender'
-]);
-$recipientWalletAddress = $client->walletAddress()->get([
- 'url' => 'https://happylifebank.example.com/recipient'
-]);
-```
-
-
-
-
-
-```go wrap
-senderWalletAddress, err := client.WalletAddress.Get(context.TODO(), op.WalletAddressGetParams{
- URL: "https://cloudninebank.example.com/sender",
-})
-if err != nil {
- log.Fatalf("Error fetching sender wallet address: %v\n", err)
-}
-
-recipientWalletAddress, err := client.WalletAddress.Get(context.TODO(), op.WalletAddressGetParams{
- URL: "https://happylifebank.example.com/recipient",
-})
-if err != nil {
- log.Fatalf("Error fetching recipient wallet address: %v\n", err)
-}
-```
-
-
-
-
-
-```java wrap
-var senderWalletAddress = client.walletAddress().get("https://cloudninebank.example.com/sender");
-var recipientWalletAddress = client.walletAddress().get("https://happylifebank.example.com/recipient");
-```
-
-
-
+
Ejemplo de respuesta
@@ -185,202 +131,7 @@ Como el remitente desea que el destinatario reciba un monto fijo de MXN 4.000 ca
Los pagos salientes requieren una concesión de autorización interactiva, que el remitente aprueba una sola vez. Mientras la concesión de autorización (y su token de acceso) sean válidos y estén dentro de sus límites (`interval` + `receiveAmount`), su aplicación puede crear pagos salientes sin volver a aprobar cada intervalo. Puede encontrar más información en las páginas del [flujo de Open Payments](/es/concepts/op-flow/#pago-saliente) y [proveedores de identidad](/es/identity/idp).
:::
-
-
-
-```ts wrap
-const pendingSenderOutgoingPaymentGrant = await client.grant.request(
- {
- url: senderWalletAddress.authServer
- },
- {
- access_token: {
- access: [
- {
- identifier: senderWalletAddress.id,
- type: 'outgoing-payment',
- actions: ['create'],
- limits: {
- interval: 'R3/2025-10-03T23:25:00Z/P1M',
- receiveAmount: {
- assetCode: 'MXN',
- assetScale: 2,
- value: '400000'
- }
- }
- }
- ]
- },
- 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
- }
- }
- }
-)
-```
-
-
-
-
-```rust wrap
-use open_payments::types::{
- AccessTokenRequest,
- AccessItem,
- OutgoingPaymentAction,
- LimitsOutgoing,
- Amount,
- Interval,
- InteractRequest,
- InteractFinish,
- GrantRequest,
-};
-use uuid::Uuid;
-
-let outgoing_access = AccessTokenRequest {
-access: vec![AccessItem::OutgoingPayment {
-identifier: sender_wallet_address.id.clone(),
-actions: vec![OutgoingPaymentAction::Create],
-limits: Some(LimitsOutgoing {
-receiver: None,
-debit_amount: None,
-receive_amount: Some(Amount {
-value: "400000".into(),
-asset_code: "MXN".into(),
-asset_scale: 2,
-}),
-interval: Some(Interval("R3/2025-10-03T23:25:00Z/P1M".to_string())),
-}),
-}],
-};
-
-let interact = InteractRequest {
-start: vec!["redirect".to_string()],
-finish: Some(InteractFinish {
-method: "redirect".to_string(),
-uri: "https://myapp.example.com/finish/{...}".to_string(),
-nonce: Uuid::new_v4().to_string(),
-}),
-};
-
-let outgoing_grant_request = GrantRequest::new(outgoing_access, Some(interact));
-
-let pending_sender_outgoing_payment_grant = client
-.grant()
-.request(&sender_wallet_address.auth_server, &outgoing_grant_request)
-.await?;
-
-```
-
-
-
-
-
-```php wrap
-$pendingSenderOutgoingPaymentGrant = $client->grant()->request(
- [
- 'url' => $senderWalletAddress->authServer
- ],
- [
- 'access_token' => [
- 'access' => [
- [
- 'identifier' => $senderWalletAddress->id,
- 'type' => 'outgoing-payment',
- 'actions' => ['create'],
- 'limits' => [
- 'interval' => 'R3/2025-10-03T23:25:00Z/P1M',
- 'receiveAmount' => [
- 'assetCode' => 'MXN',
- 'assetScale' => 2,
- 'value' => '400000',
- ]
- ]
- ]
- ]
- ],
- '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
- ]
- ]
- ]
-);
-```
-
-
-
-
-
-```go wrap
-interval := "R3/2025-10-03T23:25:00Z/P1M"
-limits := as.LimitsOutgoing{}
-if err := limits.FromLimitsOutgoing2(as.LimitsOutgoing2{
- Interval: &interval,
- ReceiveAmount: as.Amount{
- Value: "400000",
- AssetCode: "MXN",
- AssetScale: 2,
- },
-}); err != nil {
- log.Fatalf("Error creating limits: %v\n", err)
-}
-
-outgoingAccess := as.AccessOutgoing{
- Type: as.OutgoingPayment,
- Actions: []as.AccessOutgoingActions{as.AccessOutgoingActionsCreate},
- Identifier: *senderWalletAddress.Id,
- Limits: &limits,
-}
-outgoingAccessItem := as.AccessItem{}
-if err := outgoingAccessItem.FromAccessOutgoing(outgoingAccess); err != nil {
- log.Fatalf("Error creating AccessItem: %v\n", err)
-}
-outgoingAccessToken := struct {
- Access as.Access `json:"access"`
-}{
- Access: []as.AccessItem{outgoingAccessItem},
-}
-interact := &as.InteractRequest{
- Start: []as.InteractRequestStart{as.InteractRequestStartRedirect},
- Finish: &as.InteractRequestFinish{
- Method: as.Redirect,
- Uri: "https://myapp.example.com/finish/{...}",
- Nonce: NONCE,
- },
-}
-
-pendingSenderOutgoingPaymentGrant, err := client.Grant.Request(context.TODO(), op.GrantRequestParams{
- URL: *senderWalletAddress.AuthServer,
- RequestBody: as.GrantRequestWithAccessToken{
- AccessToken: outgoingAccessToken,
- Interact: interact,
- },
-})
-if err != nil {
- log.Fatalf("Error requesting outgoing payment grant: %v\n", err)
-}
-```
-
-
-
-
-
-```java wrap
-// Create an outgoing payment grant with a fixed receive amount and interval using the Java SDK types.
-// See the Java SDK docs for constructing a LimitsOutgoing object with receiveAmount and interval.
-var pendingSenderOutgoingPaymentGrant = client.auth().grant().outgoingPayment(senderWalletAddress);
-```
-
-
-
-
+
Ejemplo de respuesta
@@ -442,89 +193,7 @@ Emita la solicitud al `continue.uri` proporcionado en la respuesta de concesión
Incluya la `interact_ref` devuelta en los parámetros de consulta del URI de redirección.
-
-
-
-```ts wrap
-const senderOutgoingPaymentGrant = await client.grant.continue(
- {
- url: pendingSenderOutgoingPaymentGrant.continue.uri,
- accessToken: pendingSenderOutgoingPaymentGrant.continue.access_token.value
- },
- {
- interact_ref: interactRef
- }
-)
-```
-
-
-
-
-```rust wrap
-use open_payments::types::GrantResponse;
-let (continue_uri, continue_token) = match &pending_sender_outgoing_payment_grant {
- GrantResponse::WithInteraction { continue_, .. } | GrantResponse::WithToken { continue_, .. } => {
- (&continue_.uri, &continue_.access_token.value)
- }
-};
-let sender_outgoing_payment_grant = client
- .grant()
- .continue_grant(
- continue_uri,
- &interact_ref,
- Some(continue_token),
- )
- .await?;
-```
-
-
-
-
-
-```php wrap
-$senderOutgoingPaymentGrant = $client->grant()->continue(
- [
- 'url' => $pendingSenderOutgoingPaymentGrant->continue->uri,
- 'accessToken' => $pendingSenderOutgoingPaymentGrant->continue->access_token->value
- ],
- [
- 'interact_ref' => $interactRef
- ]
-);
-```
-
-
-
-
-
-```go wrap
-senderOutgoingPaymentGrant, err := client.Grant.Continue(context.TODO(), op.GrantContinueParams{
- URL: pendingSenderOutgoingPaymentGrant.Continue.Uri,
- AccessToken: pendingSenderOutgoingPaymentGrant.Continue.AccessToken.Value,
- InteractRef: INTERACT_REF,
-})
-if err != nil {
- log.Fatalf("Error continuing grant: %v\n", err)
-}
-```
-
-
-
-
-
-```java wrap
-var senderOutgoingPaymentGrant = client.grant().continueRequest(
- GrantContinueOptions.builder()
- .url(pendingSenderOutgoingPaymentGrant.getContinue().getUri())
- .accessToken(pendingSenderOutgoingPaymentGrant.getContinue().getAccessToken().getValue())
- .interactRef(interactRef)
- .build()
-);
-```
-
-
-
-
+
Ejemplo de respuesta
@@ -569,103 +238,7 @@ Utilice los datos del destinatario `authServer` recibidos en el paso 1 para llam
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.
-
-
-
-```ts wrap
-const recipientIncomingPaymentGrant = await client.grant.request(
- {
- url: recipientWalletAddress.authServer
- },
- {
- access_token: {
- access: [
- {
- type: 'incoming-payment',
- actions: ['create']
- }
- ]
- }
- }
-)
-```
-
-
-
-
-
-```rust wrap
-use open_payments::types::{AccessTokenRequest, AccessItem, IncomingPaymentAction, GrantRequest};
-let incoming_access = AccessTokenRequest {
- access: vec![AccessItem::IncomingPayment { actions: vec![IncomingPaymentAction::Create], identifier: None }],
-};
-let incoming_grant_request = GrantRequest::new(incoming_access, None);
-let recipient_incoming_payment_grant = client
- .grant()
- .request(&recipient_wallet_address.auth_server, &incoming_grant_request)
- .await?;
-```
-
-
-
-
-
-```php wrap
-$recipientIncomingPaymentGrant = $client->grant()->request(
- [
- 'url' => $recipientWalletAddress->authServer
- ],
- [
- 'access_token' => [
- 'access' => [
- [
- 'type' => 'incoming-payment',
- 'actions' => ['create'],
- ],
- ],
- ],
- ]
-);
-```
-
-
-
-
-
-```go wrap
-incomingAccess := as.AccessIncoming{
- Type: as.IncomingPayment,
- Actions: []as.AccessIncomingActions{as.AccessIncomingActionsCreate},
-}
-accessItem := as.AccessItem{}
-if err := accessItem.FromAccessIncoming(incomingAccess); err != nil {
- log.Fatalf("Error creating AccessItem: %v\n", err)
-}
-accessToken := struct {
- Access as.Access `json:"access"`
-}{
- Access: []as.AccessItem{accessItem},
-}
-recipientIncomingPaymentGrant, err := client.Grant.Request(context.TODO(), op.GrantRequestParams{
- URL: *recipientWalletAddress.AuthServer,
- RequestBody: as.GrantRequestWithAccessToken{AccessToken: accessToken},
-})
-if err != nil {
- log.Fatalf("Error requesting incoming payment grant: %v\n", err)
-}
-```
-
-
-
-
-
-```java wrap
-var recipientIncomingPaymentGrant = client.auth().grant().incomingPayment(recipientWalletAddress);
-```
-
-
-
-
+
Ejemplo de respuesta
@@ -701,89 +274,7 @@ Use el token de acceso devuelto en la respuesta anterior para llamar a la
-
-
-```ts wrap
-const recipientIncomingPayment = await client.incomingPayment.create(
- {
- url: recipientWalletAddress.resourceServer,
- accessToken: recipientIncomingPaymentGrant.access_token.value
- },
- {
- walletAddress: recipientWalletAddress.id
- }
-)
-```
-
-
-
-
-```rust wrap
-use open_payments::types::IncomingPaymentRequest;
-let incoming_request = IncomingPaymentRequest {
- wallet_address: recipient_wallet_address.id.clone(),
- incoming_amount: None,
- expires_at: None,
- metadata: None,
-};
-let recipient_incoming_payment = client
- .incoming_payments()
- .create(
- &recipient_wallet_address.resource_server,
- &incoming_request,
- Some(&recipient_incoming_payment_grant.access_token.value),
- )
- .await?;
-```
-
-
-
-
-
-```php wrap
-$recipientIncomingPayment = $client->incomingPayment()->create(
- [
- 'url' => $recipientWalletAddress->resourceServer,
- 'accessToken' => $recipientIncomingPaymentGrant->access_token->value
- ],
- [
- 'walletAddress' => $recipientWalletAddress->id,
- ]
-);
-```
-
-
-
-
-
-```go wrap
-recipientIncomingPayment, err := client.IncomingPayment.Create(context.TODO(), op.IncomingPaymentCreateParams{
- BaseURL: *recipientWalletAddress.ResourceServer,
- AccessToken: recipientIncomingPaymentGrant.AccessToken.Value,
- Payload: rs.CreateIncomingPaymentJSONBody{
- WalletAddressSchema: *recipientWalletAddress.Id,
- },
-})
-if err != nil {
- log.Fatalf("Error creating incoming payment: %v\n", err)
-}
-```
-
-
-
-
-
-```java wrap
-var recipientIncomingPayment = client.payment().createIncoming(
- recipientWalletAddress,
- recipientIncomingPaymentGrant
-);
-```
-
-
-
-
+
Ejemplo de respuesta
@@ -819,102 +310,7 @@ Utilice los datos del remitente `authServer` recibidos en el paso 1 para llamar
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 billetera del remitente.
-
-
-
-```ts wrap
-const senderQuoteGrant = await client.grant.request(
- {
- url: senderWalletAddress.authServer
- },
- {
- access_token: {
- access: [
- {
- type: 'quote',
- actions: ['create']
- }
- ]
- }
- }
-)
-```
-
-
-
-
-```rust wrap
-use open_payments::types::{AccessTokenRequest, AccessItem, QuoteAction, GrantRequest};
-let quote_access = AccessTokenRequest {
- access: vec![AccessItem::Quote { actions: vec![QuoteAction::Create] }],
-};
-let quote_grant_request = GrantRequest::new(quote_access, None);
-let sender_quote_grant = client
- .grant()
- .request(&sender_wallet_address.auth_server, "e_grant_request)
- .await?;
-```
-
-
-
-
-
-```php wrap
-$senderQuoteGrant = $client->grant()->request(
- [
- 'url' => $senderWalletAddress->authServer
- ],
- [
- 'access_token' => [
- 'access' => [
- [
- 'type' => 'quote',
- 'actions' => ['create']
- ]
- ]
- ]
- ]
-);
-```
-
-
-
-
-
-```go wrap
-quoteAccess := as.AccessQuote{
- Type: as.Quote,
- Actions: []as.AccessQuoteActions{as.Create},
-}
-quoteAccessItem := as.AccessItem{}
-if err := quoteAccessItem.FromAccessQuote(quoteAccess); err != nil {
- log.Fatalf("Error creating AccessItem: %v\n", err)
-}
-quoteAccessToken := struct {
- Access as.Access `json:"access"`
-}{
- Access: []as.AccessItem{quoteAccessItem},
-}
-senderQuoteGrant, err := client.Grant.Request(context.TODO(), op.GrantRequestParams{
- URL: senderWalletAddress.AuthServer,
- RequestBody: as.GrantRequestWithAccessToken{AccessToken: quoteAccessToken},
-})
-if err != nil {
- log.Fatalf("Error requesting quote grant: %v\n", err)
-}
-```
-
-
-
-
-
-```java wrap
-var senderQuoteGrant = client.auth().grant().quote(senderWalletAddress);
-```
-
-
-
-
+
Ejemplo de respuesta
@@ -952,127 +348,7 @@ Esta llamada solicita la creación de un recurso de cotización en la cuenta de
El `receiveAmount` especifica que el destinatario recibirá exactamente MXN 4.000.
-
-
-
-```ts wrap
-const senderQuote = await client.quote.create(
- {
- url: senderWalletAddress.resourceServer,
- accessToken: senderQuoteGrant.access_token.value
- },
- {
- method: 'ilp',
- walletAddress: senderWalletAddress.id,
- receiver: recipientIncomingPayment.id,
- receiveAmount: {
- value: '400000',
- assetCode: 'MXN',
- assetScale: 2
- }
- }
-)
-```
-
-
-
-
-```rust wrap
-use open_payments::types::{CreateQuoteRequest, PaymentMethodType, Receiver, Amount};
-let quote_request = CreateQuoteRequest::FixedReceiveAmountQuote {
- wallet_address: sender_wallet_address.id.clone(),
- receiver: Receiver(recipient_incoming_payment.id.clone()),
- method: PaymentMethodType::Ilp,
- receive_amount: Amount {
- value: "400000".into(),
- asset_code: "MXN".into(),
- asset_scale: 2,
- },
-};
-let sender_quote = client
- .quotes()
- .create(
- &sender_wallet_address.resource_server,
- "e_request,
- Some(&sender_quote_grant.access_token.value),
- )
- .await?;
-```
-
-
-
-
-
-```php wrap
-$senderQuote = $client->quote()->create(
- [
- 'url' => $senderWalletAddress->resourceServer,
- 'accessToken' => $senderQuoteGrant->access_token->value
- ],
- [
- 'method' => 'ilp',
- 'walletAddress' => $senderWalletAddress->id,
- 'receiver' => $recipientIncomingPayment->id,
- 'receiveAmount' => [
- 'value' => '400000',
- 'assetCode' => 'MXN',
- 'assetScale' => 2
- ]
- ]
-);
-```
-
-
-
-
-
-```go wrap
-senderQuote, err := client.Quote.Create(context.TODO(), op.QuoteCreateParams{
- BaseURL: *senderWalletAddress.ResourceServer,
- AccessToken: senderQuoteGrant.AccessToken.Value,
- Payload: rs.CreateQuoteJSONBody1{
- WalletAddressSchema: *senderWalletAddress.Id,
- Receiver: *recipientIncomingPayment.Id,
- Method: "ilp",
- ReceiveAmount: rs.Amount{
- Value: "400000",
- AssetCode: "MXN",
- AssetScale: 2,
- },
- },
-})
-if err != nil {
- log.Fatalf("Error creating quote: %v\n", err)
-}
-```
-
-
-
-
-
-```java wrap
-var senderQuote = client.quote().create(
- senderQuoteGrant.getAccess().getToken(),
- senderWalletAddress,
- recipientIncomingPayment,
- Optional.empty(),
- Optional.empty()
-);
-```
-
-
-
-
-
-La respuesta devuelve un `receiveAmount`, un `debitAmount` y demás información requerida.
-
-- `debitAmount` - El monto que el remitente debe pagar (en USD en nuestro ejemplo) después de la conversión de moneda.
-
-- `receiveAmount` - El monto que el destinatario recibirá realmente (exactamente MXN 4.000 en nuestro ejemplo).
-
-:::note[Cotizaciones con vencimiento]
-Las respuestas de cotización incluyen una marca de tiempo `expiresAt`. Cree el pago saliente antes de que la cotización expire. Si la creación falla porque la cotización expiró, solicite una nueva e intente otra vez.
-:::
+
Ejemplo de respuesta
@@ -1102,101 +378,21 @@ El siguiente ejemplo muestra una respuesta del proveedor de billetera del remite
-### 10. Solicitar la creación de un recurso de pago saliente
-
-Utilice el token de acceso devuelto en la continuación de la concesión de autorización de pago saliente (paso 5) para llamar a la [Create Outgoing Payment API](/apis/resource-server/operations/create-outgoing-payment).
-
-
-
-
-```ts wrap
-const senderOutgoingPayment = await client.outgoingPayment.create(
- {
- url: senderWalletAddress.resourceServer,
- accessToken: senderOutgoingPaymentGrant.access_token.value
- },
- {
- walletAddress: senderWalletAddress.id,
- quoteId: senderQuote.id
- }
-)
-```
-
-
-
-
-```rust wrap
-use open_payments::types::OutgoingPaymentRequest;
-let outgoing_request = OutgoingPaymentRequest::FromQuote {
- wallet_address: sender_wallet_address.id.clone(),
- quote_id: sender_quote.id.clone(),
- metadata: None,
-};
-let sender_outgoing_payment = client
- .outgoing_payments()
- .create(
- &sender_wallet_address.resource_server,
- &outgoing_request,
- Some(&sender_outgoing_payment_grant.access_token.value),
- )
- .await?;
-```
-
-
-
-
-
-```php wrap
-$senderOutgoingPayment = $client->outgoingPayment()->create(
- [
- 'url' => $senderWalletAddress->resourceServer,
- 'accessToken' => $senderOutgoingPaymentGrant->access_token->value
- ],
- [
- 'walletAddress' => $senderWalletAddress->id,
- 'quoteId' => $senderQuote->id,
- ]
-);
-```
-
-
-
-
-
-```go wrap
-var outgoingPayload rs.CreateOutgoingPaymentRequest
-if err := outgoingPayload.FromCreateOutgoingPaymentWithQuote(rs.CreateOutgoingPaymentWithQuote{
- WalletAddressSchema: *senderWalletAddress.Id,
- QuoteId: *senderQuote.Id,
-}); err != nil {
- log.Fatalf("Error creating payload: %v\n", err)
-}
+La respuesta devuelve un `receiveAmount`, un `debitAmount` y demás información requerida.
-senderOutgoingPayment, err := client.OutgoingPayment.Create(context.TODO(), op.OutgoingPaymentCreateParams{
- BaseURL: *senderWalletAddress.ResourceServer,
- AccessToken: senderOutgoingPaymentGrant.AccessToken.Value,
- Payload: outgoingPayload,
-})
-if err != nil {
- log.Fatalf("Error creating outgoing payment: %v\n", err)
-}
-```
+- `debitAmount` - El monto que el remitente debe pagar (en USD en nuestro ejemplo) después de la conversión de moneda.
-
+- `receiveAmount` - El monto que el destinatario recibirá realmente (exactamente MXN 4.000 en nuestro ejemplo).
-
+:::note[Cotizaciones con vencimiento]
+Las respuestas de cotización incluyen una marca de tiempo `expiresAt`. Cree el pago saliente antes de que la cotización expire. Si la creación falla porque la cotización expiró, solicite una nueva e intente otra vez.
+:::
-```java wrap
-var senderOutgoingPayment = client.payment().createOutgoingFromQuote(
- senderWalletAddress,
- senderQuote,
- senderOutgoingPaymentGrant
-);
-```
+### 10. Solicitar la creación de un recurso de pago saliente
-
+Utilice el token de acceso devuelto en la continuación de la concesión de autorización de pago saliente (paso 5) para llamar a la [Create Outgoing Payment API](/apis/resource-server/operations/create-outgoing-payment).
-
+
Ejemplo de respuesta
diff --git a/docs/src/content/docs/es/guides/recurring-subscription-incoming-amount.mdx b/docs/src/content/docs/es/guides/recurring-subscription-incoming-amount.mdx
index c4ebe19b..32242e4f 100644
--- a/docs/src/content/docs/es/guides/recurring-subscription-incoming-amount.mdx
+++ b/docs/src/content/docs/es/guides/recurring-subscription-incoming-amount.mdx
@@ -6,6 +6,14 @@ import { LinkOut } from '@interledger/docs-design-system'
import { Tabs, TabItem, Badge } from '@astrojs/starlight/components'
import Start from '/src/content/docs/partials/es/_grant-start-interaction.mdx'
import Finish from '/src/content/docs/partials/es/_grant-finish-interaction.mdx'
+import GetWalletAddress from '/src/content/docs/partials/code/guides/recurring-subscription-incoming-amount/_get-wallet-address.mdx'
+import GrantRequestIncomingPayment from '/src/content/docs/partials/code/guides/recurring-subscription-incoming-amount/_grant-request-incoming-payment.mdx'
+import CreateIncomingPayment from '/src/content/docs/partials/code/guides/recurring-subscription-incoming-amount/_create-incoming-payment.mdx'
+import GrantRequestQuote from '/src/content/docs/partials/code/guides/recurring-subscription-incoming-amount/_grant-request-quote.mdx'
+import CreateQuote from '/src/content/docs/partials/code/guides/recurring-subscription-incoming-amount/_create-quote.mdx'
+import GrantRequestOutgoingPayment from '/src/content/docs/partials/code/guides/recurring-subscription-incoming-amount/_grant-request-outgoing-payment.mdx'
+import CreateOutgoingPayment from '/src/content/docs/partials/code/guides/recurring-subscription-incoming-amount/_create-outgoing-payment.mdx'
+import RequestAGrantContinuation from '/src/content/docs/partials/code/guides/recurring-subscription-incoming-amount/_request-a-grant-continuation.mdx'
:::tip[Resumen]
Aprenda cómo configurar pagos de suscripción recurrentes en los que el proveedor de servicios recibe un monto fijo en intervalos regulares.
@@ -74,69 +82,7 @@ Asumamos que el cliente ya ha proporcionado su propia dirección de billetera cu
Llame a la [Get Wallet Address API](/apis/wallet-address-server/operations/get-wallet-address) para cada dirección.
-
-
-
-```ts
-const customerWalletAddress = await client.walletAddress.get({
- url: 'https://cloudninebank.example.com/customer'
-})
-const serviceProviderWalletAddress = await client.walletAddress.get({
- url: 'https://happylifebank.example.com/service-provider'
-})
-```
-
-
-
-
-```rust wrap
-let customer_wallet_address = client.wallet_address().get("https://cloudninebank.example.com/customer").await?;
-let service_provider_wallet_address = client.wallet_address().get("https://happylifebank.example.com/service-provider").await?;
-```
-
-
-
-
-```php wrap
-$customerWalletAddress = $client->walletAddress()->get([
- 'url' => 'https://cloudninebank.example.com/customer'
-]);
-$serviceProviderWalletAddress = $client->walletAddress()->get([
- 'url' => 'https://happylifebank.example.com/service-provider'
-]);
-```
-
-
-
-
-
-```go wrap
-customerWalletAddress, err := client.WalletAddress.Get(context.TODO(), op.WalletAddressGetParams{
- URL: "https://cloudninebank.example.com/customer",
-})
-if err != nil {
- log.Fatalf("Error fetching customer wallet address: %v\n", err)
-}
-
-serviceProviderWalletAddress, err := client.WalletAddress.Get(context.TODO(), op.WalletAddressGetParams{
- URL: "https://happylifebank.example.com/service-provider",
-})
-if err != nil {
- log.Fatalf("Error fetching service provider wallet address: %v\n", err)
-}
-```
-
-
-
-
-
-```java wrap
-var customerWalletAddress = client.walletAddress().get("https://cloudninebank.example.com/customer");
-var serviceProviderWalletAddress = client.walletAddress().get("https://happylifebank.example.com/service-provider");
-```
-
-
-
+
Ejemplo de respuesta
@@ -173,103 +119,7 @@ Utilice los datos del proveedor de servicio `authServer`, recibidos en el paso a
Esta llamada obtiene un token de acceso que le permite solicitar la creación de un recurso de pago entrante en la cuenta de billetera del proveedor de servicio.
-
-
-
-```ts wrap
-const serviceProviderIncomingPaymentGrant = await client.grant.request(
- {
- url: serviceProviderWalletAddress.authServer
- },
- {
- access_token: {
- access: [
- {
- type: 'incoming-payment',
- actions: ['create']
- }
- ]
- }
- }
-)
-```
-
-
-
-
-```rust wrap
-use open_payments::types::{AccessTokenRequest, AccessItem, IncomingPaymentAction, GrantRequest};
-let incoming_access = AccessTokenRequest {
- access: vec![AccessItem::IncomingPayment { actions: vec![IncomingPaymentAction::Create], identifier: None }],
-};
-let incoming_grant_request = GrantRequest::new(incoming_access, None);
-let service_provider_incoming_payment_grant = client
- .grant()
- .request(&service_provider_wallet_address.auth_server, &incoming_grant_request)
- .await?;
-```
-
-
-
-
-```php wrap
-$serviceProviderIncomingPaymentGrant = $client->grant()->request(
- [
- 'url' => $serviceProviderWalletAddress->authServer
- ],
- [
- 'access_token' => [
- 'access' => [
- [
- 'type' => 'incoming-payment',
- 'actions' => ['create']
- ]
- ]
- ]
- ]
-);
-```
-
-
-
-
-
-```go wrap
-incomingAccess := as.AccessIncoming{
- Type: as.IncomingPayment,
- Actions: []as.AccessIncomingActions{as.AccessIncomingActionsCreate},
-}
-accessItem := as.AccessItem{}
-if err := accessItem.FromAccessIncoming(incomingAccess); err != nil {
- log.Fatalf("Error creating AccessItem: %v\n", err)
-}
-accessToken := struct {
- Access as.Access `json:"access"`
-}{
- Access: []as.AccessItem{accessItem},
-}
-
-serviceProviderIncomingPaymentGrant, err := client.Grant.Request(context.TODO(), op.GrantRequestParams{
- URL: *serviceProviderWalletAddress.AuthServer,
- RequestBody: as.GrantRequestWithAccessToken{AccessToken: accessToken},
-})
-if err != nil {
- log.Fatalf("Error requesting incoming payment grant: %v\n", err)
-}
-```
-
-
-
-
-
-```java wrap
-var serviceProviderIncomingPaymentGrant = client.auth().grant().incomingPayment(
- serviceProviderWalletAddress
-);
-```
-
-
-
+
Ejemplo de respuesta
@@ -305,108 +155,7 @@ Use el token de acceso devuelto en la respuesta anterior para llamar a la
-
-
-```ts wrap
-const serviceProviderIncomingPayment = await client.incomingPayment.create(
- {
- url: serviceProviderWalletAddress.resourceServer,
- accessToken: serviceProviderIncomingPaymentGrant.access_token.value
- },
- {
- walletAddress: serviceProviderWalletAddress.id,
- incomingAmount: {
- value: '1500', // The amount the service provider expects to receive in the first payment
- assetCode: 'USD',
- assetScale: 2
- }
- }
-)
-```
-
-
-
-
-```rust wrap
-use open_payments::types::{IncomingPaymentRequest, Amount};
-let incoming_request = IncomingPaymentRequest {
- wallet_address: service_provider_wallet_address.id.clone(),
- incoming_amount: Some(Amount {
- value: "1500".into(),
- asset_code: "USD".into(),
- asset_scale: 2,
- }),
- expires_at: None,
- metadata: None,
-};
-let service_provider_incoming_payment = client
- .incoming_payments()
- .create(
- &service_provider_wallet_address.resource_server,
- &incoming_request,
- Some(&service_provider_incoming_payment_grant.access_token.value),
- )
- .await?;
-```
-
-
-
-
-
-```php wrap
-$serviceProviderIncomingPayment = $client->incomingPayment()->create(
- [
- 'url' => $serviceProviderWalletAddress->resourceServer,
- 'accessToken' => $serviceProviderIncomingPaymentGrant->access_token->value
- ],
- [
- 'walletAddress' => $serviceProviderWalletAddress->id,
- 'incomingAmount' => [
- 'value' => '1500', // The amount the service provider expects to receive in the first payment
- 'assetCode' => 'USD',
- 'assetScale' => 2
- ],
- ]
-);
-```
-
-
-
-
-
-```go wrap
-serviceProviderIncomingPayment, err := client.IncomingPayment.Create(context.TODO(), op.IncomingPaymentCreateParams{
- BaseURL: *serviceProviderWalletAddress.ResourceServer,
- AccessToken: serviceProviderIncomingPaymentGrant.AccessToken.Value,
- Payload: rs.CreateIncomingPaymentJSONBody{
- WalletAddressSchema: *serviceProviderWalletAddress.Id,
- IncomingAmount: &rs.Amount{
- Value: "1500",
- AssetCode: "USD",
- AssetScale: 2,
- },
- },
-})
-if err != nil {
- log.Fatalf("Error creating incoming payment: %v\n", err)
-}
-```
-
-
-
-
-
-```java wrap
-var serviceProviderIncomingPayment = client.payment().createIncoming(
- serviceProviderWalletAddress,
- serviceProviderIncomingPaymentGrant,
- BigDecimal.valueOf(15.00)
-);
-```
-
-
-
+
Ejemplo de respuesta
@@ -447,104 +196,7 @@ Utilice los datos del consumidor `authServer`, recibidos en el paso 1, para llam
Esta llamada obtiene un token de acceso que le permite solicitar la creación de un recurso de cotización en la cuenta de billetera del cliente.
-
-
-
-```ts wrap
-const customerQuoteGrant = await client.grant.request(
- {
- url: customerWalletAddress.authServer
- },
- {
- access_token: {
- access: [
- {
- type: 'quote',
- actions: ['create']
- }
- ]
- }
- }
-)
-```
-
-
-
-
-```rust wrap
-use open_payments::types::{AccessTokenRequest, AccessItem, QuoteAction, GrantRequest};
-let quote_access = AccessTokenRequest {
- access: vec![AccessItem::Quote { actions: vec![QuoteAction::Create] }],
-};
-let quote_grant_request = GrantRequest::new(quote_access, None);
-let customer_quote_grant = client
- .grant()
- .request(&customer_wallet_address.auth_server, "e_grant_request)
- .await?;
-```
-
-
-
-
-
-```php wrap
-$customerQuoteGrant = $client->grant()->request(
- [
- 'url' => $customerWalletAddress->authServer
- ],
- [
- 'access_token' => [
- 'access' => [
- [
- 'type' => 'quote',
- 'actions' => ['create']
- ]
- ]
- ]
- ]
-);
-```
-
-
-
-
-
-```go wrap
-quoteAccess := as.AccessQuote{
- Type: as.Quote,
- Actions: []as.AccessQuoteActions{as.Create},
-}
-quoteAccessItem := as.AccessItem{}
-if err := quoteAccessItem.FromAccessQuote(quoteAccess); err != nil {
- log.Fatalf("Error creating AccessItem: %v\n", err)
-}
-quoteAccessToken := struct {
- Access as.Access `json:"access"`
-}{
- Access: []as.AccessItem{quoteAccessItem},
-}
-
-customerQuoteGrant, err := client.Grant.Request(context.TODO(), op.GrantRequestParams{
- URL: *customerWalletAddress.AuthServer,
- RequestBody: as.GrantRequestWithAccessToken{AccessToken: quoteAccessToken},
-})
-if err != nil {
- log.Fatalf("Error requesting quote grant: %v\n", err)
-}
-```
-
-
-
-
-
-```java wrap
-var customerQuoteGrant = client.auth().grant().quote(
- customerWalletAddress
-);
-```
-
-
-
+
Ejemplo de respuesta
@@ -582,105 +234,7 @@ Esta llamada solicita que se cree un recurso de cotización en la cuenta de la b
La solicitud debe contener el `receiver`, que es la `id` del pago entrante del proveedor de servicio. La `id` se indicó en la respuesta de la API Crear pago entrante en el paso 3.
-
-
-
-```ts wrap
-const customerQuote = await client.quote.create(
- {
- url: customerWalletAddress.resourceServer,
- accessToken: customerQuoteGrant.access_token.value
- },
- {
- method: 'ilp',
- walletAddress: customerWalletAddress.id,
- receiver: serviceProviderIncomingPayment.id
- }
-)
-```
-
-
-
-
-```rust wrap
-use open_payments::types::{CreateQuoteRequest, PaymentMethodType, Receiver};
-let quote_request = CreateQuoteRequest::NoAmountQuote {
- wallet_address: customer_wallet_address.id.clone(),
- receiver: Receiver(service_provider_incoming_payment.id.clone()),
- method: PaymentMethodType::Ilp,
-};
-let customer_quote = client
- .quotes()
- .create(
- &customer_wallet_address.resource_server,
- "e_request,
- Some(&customer_quote_grant.access_token.value),
- )
- .await?;
-```
-
-
-
-
-
-```php wrap
-$customerQuote = $client->quote()->create(
- [
- 'url' => $customerWalletAddress->resourceServer,
- 'accessToken' => $customerQuoteGrant->access_token->value
- ],
- [
- 'method' => 'ilp',
- 'walletAddress' => $customerWalletAddress->id,
- 'receiver' => $serviceProviderIncomingPayment->id,
- ]
-);
-```
-
-
-
-
-
-```go wrap
-customerQuote, err := client.Quote.Create(context.TODO(), op.QuoteCreateParams{
- BaseURL: *customerWalletAddress.ResourceServer,
- AccessToken: customerQuoteGrant.AccessToken.Value,
- Payload: rs.CreateQuoteJSONBody0{
- WalletAddressSchema: *customerWalletAddress.Id,
- Receiver: *serviceProviderIncomingPayment.Id,
- Method: "ilp",
- },
-})
-if err != nil {
- log.Fatalf("Error creating quote: %v\n", err)
-}
-```
-
-
-
-
-
-```java wrap
-var customerQuote = client.quote().create(
- customerQuoteGrant.getAccess().getToken(),
- customerWalletAddress,
- serviceProviderIncomingPayment,
- Optional.empty(),
- Optional.empty()
-);
-```
-
-
-
-
-La respuesta devuelve un `debitAmount`, un `receiveAmount` y demás información requerida.
-
-- `debitAmount` - El monto que se cobrará al cliente.
-- `receiveAmount` - El valor del `incomingAmount` del recurso de pago entrante.
-
-:::note[Cotizaciones con vencimiento]
-Las respuestas de cotización incluyen una marca de tiempo `expiresAt`. Cree el pago saliente antes de que la cotización expire. Si la creación falla porque la cotización expiró, solicite una nueva e intente otra vez.
-:::
+
Ejemplo de respuesta
@@ -710,6 +264,15 @@ El siguiente ejemplo muestra una respuesta del proveedor de billetera del client
+La respuesta devuelve un `debitAmount`, un `receiveAmount` y demás información requerida.
+
+- `debitAmount` - El monto que se cobrará al cliente.
+- `receiveAmount` - El valor del `incomingAmount` del recurso de pago entrante.
+
+:::note[Cotizaciones con vencimiento]
+Las respuestas de cotización incluyen una marca de tiempo `expiresAt`. Cree el pago saliente antes de que la cotización expire. Si la creación falla porque la cotización expiró, solicite una nueva e intente otra vez.
+:::
+
### 6. Solicitar una concesión de autorización interactiva para un pago saliente
Utilice la información del cliente `authServer` recibida en el paso 1 para llamar a la [Grant Request API](/apis/auth-server/operations/post-request).
@@ -722,206 +285,7 @@ Los pagos salientes requieren una concesión de autorización interactiva. Este
Para los pagos recurrentes, incluya la propiedad `interval` para especificar la frecuencia con la que debe realizarse el pago. Recuerde que el cliente quiere pagar $15 USD al mes durante 12 meses.
-
-
-
-```ts wrap
-const pendingCustomerOutgoingPaymentGrant = await client.grant.request(
- {
- url: customerWalletAddress.authServer
- },
- {
- access_token: {
- access: [
- {
- identifier: customerWalletAddress.id,
- type: 'outgoing-payment',
- actions: ['create', 'read'],
- limits: {
- debitAmount: {
- assetCode: 'USD',
- assetScale: 2,
- value: '1500'
- },
- interval: 'R12/2025-10-14T00:03:00Z/P1M'
- }
- }
- ]
- },
- interact: {
- start: ['redirect'],
- finish: {
- method: 'redirect',
- uri: 'https://myapp.example.com/finish/{...}', // where to redirect the customer after they've completed interaction
- nonce: NONCE
- }
- }
- }
-)
-```
-
-
-
-
-```rust wrap
-use open_payments::types::{
- AccessTokenRequest,
- AccessItem,
- OutgoingPaymentAction,
- LimitsOutgoing,
- Amount,
- Interval,
- InteractRequest,
- InteractFinish,
- GrantRequest,
-};
-use uuid::Uuid;
-
-let outgoing_access = AccessTokenRequest {
-access: vec![AccessItem::OutgoingPayment {
-identifier: customer_wallet_address.id.clone(),
-actions: vec![OutgoingPaymentAction::Create, OutgoingPaymentAction::Read],
-limits: Some(LimitsOutgoing {
-receiver: None,
-debit_amount: Some(Amount {
-value: "1500".into(),
-asset_code: "USD".into(),
-asset_scale: 2,
-}),
-receive_amount: None,
-interval: Some(Interval("R12/2025-10-14T00:03:00Z/P1M".to_string())),
-}),
-}],
-};
-
-let interact = InteractRequest {
-start: vec!["redirect".to_string()],
-finish: Some(InteractFinish {
-method: "redirect".to_string(),
-uri: "https://myapp.example.com/finish/{...}".to_string(),
-nonce: Uuid::new_v4().to_string(),
-}),
-};
-
-let outgoing_grant_request = GrantRequest::new(outgoing_access, Some(interact));
-
-let pending_customer_outgoing_payment_grant = client
-.grant()
-.request(&customer_wallet_address.auth_server, &outgoing_grant_request)
-.await?;
-
-```
-
-
-
-
-
-```php wrap
-$pendingCustomerOutgoingPaymentGrant = $client->grant()->request(
- [
- 'url' => $customerWalletAddress->authServer
- ],
- [
- 'access_token' => [
- 'access' => [
- [
- 'identifier' => $customerWalletAddress->id,
- 'type' => 'outgoing-payment',
- 'actions' => ['create', 'read'],
- 'limits' => [
- 'debitAmount' => [
- 'assetCode' => 'USD',
- 'assetScale' => 2,
- 'value' => '1500',
- ],
- 'interval' => 'R12/2025-10-14T00:03:00Z/P1M'
- ]
- ]
- ]
- ],
- 'interact' => [
- 'start' => ['redirect'],
- 'finish' => [
- 'method' => 'redirect',
- 'uri' => 'https://myapp.example.com/finish/{...}', // where to redirect the customer after they've completed interaction
- 'nonce' => NONCE
- ]
- ]
- ]
-);
-```
-
-
-
-
-
-```go wrap
-interval := "R12/2025-10-14T00:03:00Z/P1M"
-limits := as.LimitsOutgoing{}
-if err := limits.FromLimitsOutgoing1(as.LimitsOutgoing1{
- Interval: &interval,
- DebitAmount: as.Amount{
- Value: "1500",
- AssetCode: "USD",
- AssetScale: 2,
- },
-}); err != nil {
- log.Fatalf("Error creating limits: %v\n", err)
-}
-
-outgoingAccess := as.AccessOutgoing{
- Type: as.OutgoingPayment,
- Actions: []as.AccessOutgoingActions{as.AccessOutgoingActionsCreate, as.AccessOutgoingActionsRead},
- Identifier: *customerWalletAddress.Id,
- Limits: &limits,
-}
-outgoingAccessItem := as.AccessItem{}
-if err := outgoingAccessItem.FromAccessOutgoing(outgoingAccess); err != nil {
- log.Fatalf("Error creating AccessItem: %v\n", err)
-}
-outgoingAccessToken := struct {
- Access as.Access `json:"access"`
-}{
- Access: []as.AccessItem{outgoingAccessItem},
-}
-interact := &as.InteractRequest{
- Start: []as.InteractRequestStart{as.InteractRequestStartRedirect},
- Finish: &as.InteractRequestFinish{
- Method: as.Redirect,
- Uri: "https://myapp.example.com/finish/{...}", // where to redirect the customer after they've completed interaction
- Nonce: NONCE,
- },
-}
-
-pendingCustomerOutgoingPaymentGrant, err := client.Grant.Request(context.TODO(), op.GrantRequestParams{
- URL: *customerWalletAddress.AuthServer,
- RequestBody: as.GrantRequestWithAccessToken{
- AccessToken: outgoingAccessToken,
- Interact: interact,
- },
-})
-if err != nil {
- log.Fatalf("Error requesting outgoing payment grant: %v\n", err)
-}
-```
-
-
-
-
-
-```java wrap
-var urlToOpen = "https://myapp.example.com/finish/{...}";
-
-var opContinueInteract = client.auth().grant().continuation(
- customerWalletAddress,
- customerQuote.getDebitAmount(),
- URI.create(urlToOpen),
- "NONCE"
-);
-```
-
-
-
+
Ejemplo de respuesta
@@ -979,84 +343,7 @@ Emita la solicitud al `continue.uri` proporcionado en la respuesta de concesión
Incluya la `interact_ref` devuelta en los parámetros de consulta del URI de redirección.
-
-
-
- ```ts wrap
- const customerOutgoingPaymentGrant = await client.grant.continue(
- {
- url: customerOutgoingPaymentGrant.continue.uri,
- accessToken: customerOutgoingPaymentGrant.continue.access_token.value
- },
- {
- interact_ref: interactRef
- }
- )
- ```
-
-
-
-
-```rust wrap
-use open_payments::types::GrantResponse;
-let (continue_uri, continue_token) = match &pending_customer_outgoing_payment_grant {
- GrantResponse::WithInteraction { continue_, .. } | GrantResponse::WithToken { continue_, .. } => {
- (&continue_.uri, &continue_.access_token.value)
- }
-};
-let customer_outgoing_payment_grant = client
- .grant()
- .continue_grant(
- continue_uri,
- &interact_ref,
- Some(continue_token),
- )
- .await?;
-```
-
-
-
-
-
-```php wrap
-$customerOutgoingPaymentGrant = $client->grant()->continue(
- [
- 'url' => $pendingCustomerOutgoingPaymentGrant->continue->uri,
- 'accessToken' => $pendingCustomerOutgoingPaymentGrant->continue->access_token->value
- ],
- [
- 'interact_ref' => $interactRef
- ]
-);
-```
-
-
-
-
-
-```go wrap
-customerOutgoingPaymentGrant, err := client.Grant.Continue(context.TODO(), op.GrantContinueParams{
- URL: pendingCustomerOutgoingPaymentGrant.Continue.Uri,
- AccessToken: pendingCustomerOutgoingPaymentGrant.Continue.AccessToken.Value,
- InteractRef: INTERACT_REF,
-})
-if err != nil {
- log.Fatalf("Error continuing grant: %v\n", err)
-}
-```
-
-
-
-
-```java wrap
-var customerOutgoingPaymentGrant = client.auth().grant().finalize(
- opContinueInteract,
- interactRef
-);
-```
-
-
-
+
Ejemplo de respuesta
@@ -1101,95 +388,7 @@ Utilice el token de acceso devuelto en el paso 9 para llamar a la
-
-
-```ts wrap
-const customerOutgoingPayment = await client.outgoingPayment.create(
- {
- url: customerWalletAddress.resourceServer,
- accessToken: customerOutgoingPaymentGrant.access_token.value
- },
- {
- walletAddress: customerWalletAddress.id,
- quoteId: customerQuote.id
- }
-)
-```
-
-
-
-
-```rust wrap
-use open_payments::types::OutgoingPaymentRequest;
-let outgoing_request = OutgoingPaymentRequest::FromQuote {
- wallet_address: customer_wallet_address.id.clone(),
- quote_id: customer_quote.id.clone(),
- metadata: None,
-};
-let customer_outgoing_payment = client
- .outgoing_payments()
- .create(
- &customer_wallet_address.resource_server,
- &outgoing_request,
- Some(&customer_outgoing_payment_grant.access_token.value),
- )
- .await?;
-```
-
-
-
-
-
-```php wrap
-$customerOutgoingPayment = $client->outgoingPayment()->create(
- [
- 'url' => $customerWalletAddress->resourceServer,
- 'accessToken' => $customerOutgoingPaymentGrant->access_token->value
- ],
- [
- 'walletAddress' => $customerWalletAddress->id,
- 'quoteId' => $customerQuote->id
- ]
-);
-```
-
-
-
-
-
-```go wrap
-var outgoingPayload rs.CreateOutgoingPaymentRequest
-if err := outgoingPayload.FromCreateOutgoingPaymentWithQuote(rs.CreateOutgoingPaymentWithQuote{
- WalletAddressSchema: *customerWalletAddress.Id,
- QuoteId: *customerQuote.Id,
-}); err != nil {
- log.Fatalf("Error creating payload: %v\n", err)
-}
-
-customerOutgoingPayment, err := client.OutgoingPayment.Create(context.TODO(), op.OutgoingPaymentCreateParams{
- BaseURL: *customerWalletAddress.ResourceServer,
- AccessToken: customerOutgoingPaymentGrant.AccessToken.Value,
- Payload: outgoingPayload,
-})
-if err != nil {
- log.Fatalf("Error creating outgoing payment: %v\n", err)
-}
-```
-
-
-
-
-```java wrap
-var customerOutgoingPayment = client.payment().createOutgoing(
- customerOutgoingPaymentGrant,
- customerWalletAddress,
- customerQuote
-);
-```
-
-
-
+
Ejemplo de respuesta
diff --git a/docs/src/content/docs/es/guides/split-payments.mdx b/docs/src/content/docs/es/guides/split-payments.mdx
index 41599474..f801e26c 100644
--- a/docs/src/content/docs/es/guides/split-payments.mdx
+++ b/docs/src/content/docs/es/guides/split-payments.mdx
@@ -7,6 +7,14 @@ import { Tabs, TabItem, Badge } from '@astrojs/starlight/components'
import InteractionReq from '/src/content/docs/partials/es/_interaction-required.mdx'
import Start from '/src/content/docs/partials/es/_grant-start-interaction.mdx'
import Finish from '/src/content/docs/partials/es/_grant-finish-interaction.mdx'
+import GetWalletAddress from '/src/content/docs/partials/code/guides/split-payments/_get-wallet-address.mdx'
+import GrantRequestIncomingPayments from '/src/content/docs/partials/code/guides/split-payments/_grant-request-incoming-payments.mdx'
+import CreateIncomingPayments from '/src/content/docs/partials/code/guides/split-payments/_create-incoming-payments.mdx'
+import GrantRequestQuote from '/src/content/docs/partials/code/guides/split-payments/_grant-request-quote.mdx'
+import CreateQuotes from '/src/content/docs/partials/code/guides/split-payments/_create-quotes.mdx'
+import GrantRequestOutgoingPayment from '/src/content/docs/partials/code/guides/split-payments/_grant-request-outgoing-payment.mdx'
+import CreateOutgoingPayments from '/src/content/docs/partials/code/guides/split-payments/_create-outgoing-payments.mdx'
+import RequestAGrantContinuation from '/src/content/docs/partials/code/guides/split-payments/_request-a-grant-continuation.mdx'
:::tip[Resumen]
Conozca cómo tomar un único pago y dividir el valor entre varios destinatarios.
@@ -61,81 +69,7 @@ Supongamos que la dirección de la billetera ya se encuentra guardada en su plat
Llame a la [Get Wallet Address](/es/apis/wallet-address-server/operations/get-wallet-address) para cada dirección.
-
-
- ```ts
- const customerWalletAddress = await client.walletAddress.get({
- url: 'https://cloudninebank.example.com/customer'
- })
-
- const merchantWalletAddress = await client.walletAddress.get({
- url: 'https://happylifebank.example.com/merchant'
- })
-
- const platformWalletAddress = await client.walletAddress.get({
- url: 'https://coolwallet.example.com/platform'
- })
- ```
-
-
-
-
-```rust wrap
-let customer_wallet_address = client.wallet_address().get("https://cloudninebank.example.com/customer").await?;
-let merchant_wallet_address = client.wallet_address().get("https://happylifebank.example.com/merchant").await?;
-let platform_wallet_address = client.wallet_address().get("https://coolwallet.example.com/platform").await?;
-```
-
-
-
-
- ```php wrap
- $customerWalletAddress = $client->walletAddress()->get([
- 'url' => 'https://cloudninebank.example.com/customer'
- ]);
- $merchantWalletAddress = $client->walletAddress()->get([
- 'url' => 'https://happylifebank.example.com/merchant'
- ]);
- $platformWalletAddress = $client->walletAddress()->get([
- 'url' => 'https://coolwallet.example.com/platform'
- ]);
- ```
-
-
-
-
- ```go wrap
- customerWalletAddress, err := client.WalletAddress.Get(context.TODO(), op.WalletAddressGetParams{
- URL: "https://cloudninebank.example.com/customer",
- })
- if err != nil {
- log.Fatalf("Error fetching customer wallet address: %v\n", err)
- }
- merchantWalletAddress, err := client.WalletAddress.Get(context.TODO(), op.WalletAddressGetParams{
- URL: "https://happylifebank.example.com/merchant",
- })
- if err != nil {
- log.Fatalf("Error fetching merchant wallet address: %v\n", err)
- }
- platformWalletAddress, err := client.WalletAddress.Get(context.TODO(), op.WalletAddressGetParams{
- URL: "https://coolwallet.example.com/platform",
- })
- if err != nil {
- log.Fatalf("Error fetching platform wallet address: %v\n", err)
- }
- ```
-
-
-
-
-```java wrap
-var customerWalletAddress = client.walletAddress().get("https://cloudninebank.example.com/customer");
-var merchantWalletAddress = client.walletAddress().get("https://happylifebank.example.com/merchant");
-var platformWalletAddress = client.walletAddress().get("https://coolwallet.example.com/platform");
-```
-
-
-
+
Ejemplo de respuesta
@@ -180,158 +114,7 @@ El propósito de estas llamadas consiste en obtener tókenes de acceso que permi
Si usted y el comerciante utilizan la misma entidad que administra cuentas, y la información del servidor de autorización que se recibió es la misma para ambos, solo necesita una concesión `incomingPayment`.
:::
-
-
-
-```ts wrap
-// Merchant
-const merchantIncomingPaymentGrant = await client.grant.request(
- {
- url: merchantWalletAddress.authServer
- },
- {
- access_token: {
- access: [
- {
- type: 'incoming-payment',
- actions: ['read', 'create']
- }
- ]
- }
- }
-)
-// Platform
-const platformIncomingPaymentGrant = await client.grant.request(
- {
- url: platformWalletAddress.authServer
- },
- {
- access_token: {
- access: [
- {
- type: 'incoming-payment',
- actions: ['read', 'create']
- }
- ]
- }
- }
-)
-```
-
-
-
-
-
-```rust wrap
-use open_payments::types::{AccessTokenRequest, AccessItem, IncomingPaymentAction, GrantRequest};
-let incoming_access = AccessTokenRequest {
- access: vec![AccessItem::IncomingPayment { actions: vec![IncomingPaymentAction::Create], identifier: None }],
-};
-let merchant_grant_request = GrantRequest::new(incoming_access.clone(), None);
-let platform_grant_request = GrantRequest::new(incoming_access, None);
-let merchant_incoming_payment_grant = client
- .grant()
- .request(&merchant_wallet_address.auth_server, &merchant_grant_request)
- .await?;
-let platform_incoming_payment_grant = client
- .grant()
- .request(&platform_wallet_address.auth_server, &platform_grant_request)
- .await?;
-```
-
-
-
-
-
-```php wrap
-// Merchant
-$merchantIncomingPaymentGrant = $client->grant()->request(
- [
- 'url' => $merchantWalletAddress->authServer
- ],
- [
- 'access_token' => [
- 'access' => [
- [
- 'type' => 'incoming-payment',
- 'actions' => ['create']
- ]
- ]
- ]
- ]
-);
-// Platform
-$platformIncomingPaymentGrant = $client->grant()->request(
- [
- 'url' => $platformWalletAddress->authServer
- ],
- [
- 'access_token' => [
- 'access' => [
- [
- 'type' => 'incoming-payment',
- 'actions' => ['create']
- ]
- ]
- ]
- ]
-);
-```
-
-
-
-
-
-```go wrap
-incomingAccess := as.AccessIncoming{
- Type: as.IncomingPayment,
- Actions: []as.AccessIncomingActions{as.AccessIncomingActionsCreate},
-}
-accessItem := as.AccessItem{}
-if err := accessItem.FromAccessIncoming(incomingAccess); err != nil {
- log.Fatalf("Error creating AccessItem: %v\n", err)
-}
-accessToken := struct {
- Access as.Access `json:"access"`
-}{
- Access: []as.AccessItem{accessItem},
-}
-// Merchant
-merchantIncomingPaymentGrant, err := client.Grant.Request(context.TODO(), op.GrantRequestParams{
- URL: *merchantWalletAddress.AuthServer,
- RequestBody: as.GrantRequestWithAccessToken{AccessToken: accessToken},
-})
-if err != nil {
- log.Fatalf("Error requesting merchant incoming payment grant: %v\n", err)
-}
-// Platform
-platformIncomingPaymentGrant, err := client.Grant.Request(context.TODO(), op.GrantRequestParams{
- URL: *platformWalletAddress.AuthServer,
- RequestBody: as.GrantRequestWithAccessToken{AccessToken: accessToken},
-})
-if err != nil {
- log.Fatalf("Error requesting platform incoming payment grant: %v\n", err)
-}
-```
-
-
-
-
-
-```java wrap
-// Merchant
-var merchantIncomingPaymentGrant = client.auth().grant().incomingPayment(
- merchantWalletAddress
-);
-
-// Platform
-var platformIncomingPaymentGrant = client.auth().grant().incomingPayment(
- platformWalletAddress
-);
-```
-
-
-
+
Ejemplo de respuesta
@@ -378,167 +161,7 @@ Incluya lo siguiente en ambas solicitudes, junto con cualquier otro parámetro r
El `value` total de $100 es `10000`. El comerciante recibirá el 99 % (`9900`) y usted recibirá el 1 % (`100`).
-
-
-
-```ts wrap
-// Merchant
-const merchantIncomingPayment = await client.incomingPayment.create(
- {
- url: merchantWalletAddress.resourceServer,
- accessToken: merchantIncomingPaymentGrant.access_token.value
- },
- {
- walletAddress: merchantWalletAddress.id,
- incomingAmount: {
- value: '9900',
- assetCode: 'USD',
- assetScale: 2
- }
- }
-)
-// Platform
-const platformIncomingPayment = await client.incomingPayment.create(
- {
- url: platformWalletAddress.resourceServer,
- accessToken: platformIncomingPaymentGrant.access_token.value
- },
- {
- walletAddress: platformWalletAddress.id,
- incomingAmount: {
- value: '100',
- assetCode: 'USD',
- assetScale: 2
- }
- }
-)
-```
-
-
-
-
-```rust wrap
-use open_payments::types::{IncomingPaymentRequest, Amount};
-let merchant_request = IncomingPaymentRequest {
- wallet_address: merchant_wallet_address.id.clone(),
- incoming_amount: Some(Amount { value: "9900".into(), asset_code: "USD".into(), asset_scale: 2 }),
- expires_at: None,
- metadata: None,
-};
-let platform_request = IncomingPaymentRequest {
- wallet_address: platform_wallet_address.id.clone(),
- incoming_amount: Some(Amount { value: "100".into(), asset_code: "USD".into(), asset_scale: 2 }),
- expires_at: None,
- metadata: None,
-};
-let merchant_incoming_payment = client
- .incoming_payments()
- .create(&merchant_wallet_address.resource_server, &merchant_request, Some(&merchant_incoming_payment_grant.access_token.value))
- .await?;
-let platform_incoming_payment = client
- .incoming_payments()
- .create(&platform_wallet_address.resource_server, &platform_request, Some(&platform_incoming_payment_grant.access_token.value))
- .await?;
-```
-
-
-
-
-
-```php wrap
-// Merchant
-$merchantIncomingPayment = $client->incomingPayment()->create(
- [
- 'url' => $merchantWalletAddress->resourceServer,
- 'accessToken' => $merchantIncomingPaymentGrant->access_token->value
- ],
- [
- 'walletAddress' => $merchantWalletAddress->id,
- 'incomingAmount' => [
- 'value' => '9900',
- 'assetCode' => 'USD',
- 'assetScale' => 2
- ]
- ]
-);
-// Platform
-$platformIncomingPayment = $client->incomingPayment()->create(
- [
- 'url' => $platformWalletAddress->resourceServer,
- 'accessToken' => $platformIncomingPaymentGrant->access_token->value
- ],
- [
- 'walletAddress' => $platformWalletAddress->id,
- 'incomingAmount' => [
- 'value' => '100',
- 'assetCode' => 'USD',
- 'assetScale' => 2
- ]
- ]
-);
-```
-
-
-
-
-
-```go wrap
-// Merchant
-merchantIncomingPayment, err := client.IncomingPayment.Create(context.TODO(), op.IncomingPaymentCreateParams{
- BaseURL: *merchantWalletAddress.ResourceServer,
- AccessToken: merchantIncomingPaymentGrant.AccessToken.Value,
- Payload: rs.CreateIncomingPaymentJSONBody{
- WalletAddressSchema: *merchantWalletAddress.Id,
- IncomingAmount: &rs.Amount{
- Value: "9900",
- AssetCode: "USD",
- AssetScale: 2,
- },
- },
-})
-if err != nil {
- log.Fatalf("Error creating merchant incoming payment: %v\n", err)
-}
-// Platform
-platformIncomingPayment, err := client.IncomingPayment.Create(context.TODO(), op.IncomingPaymentCreateParams{
- BaseURL: *platformWalletAddress.ResourceServer,
- AccessToken: platformIncomingPaymentGrant.AccessToken.Value,
- Payload: rs.CreateIncomingPaymentJSONBody{
- WalletAddressSchema: *platformWalletAddress.Id,
- IncomingAmount: &rs.Amount{
- Value: "100",
- AssetCode: "USD",
- AssetScale: 2,
- },
- },
-})
-if err != nil {
- log.Fatalf("Error creating platform incoming payment: %v\n", err)
-}
-```
-
-
-
-
-
-```java wrap
-// Merchant receives 99.00 USD (value 9900, scale 2)
-var merchantIncomingPayment = client.payment().createIncoming(
- merchantWalletAddress,
- merchantIncomingPaymentGrant,
- BigDecimal.valueOf(99.00)
-);
-
-// Platform receives 1.00 USD (value 100, scale 2)
-var platformIncomingPayment = client.payment().createIncoming(
- platformWalletAddress,
- platformIncomingPaymentGrant,
- BigDecimal.valueOf(1.00)
-);
-```
-
-
-
+
Ejemplo de respuesta
@@ -579,103 +202,7 @@ Utilice los datos del consumidor `authServer`, recibidos en el paso 1, para llam
El propósito de esta llamada consiste en obtener un token de acceso que permita a su plataforma solicitar la creación de recursos de cotización en la cuenta de la billetera del consumidor.
-
-
-
-```ts wrap
-const customerQuoteGrant = await client.grant.request(
- {
- url: customerWalletAddress.authServer
- },
- {
- access_token: {
- access: [
- {
- type: 'quote',
- actions: ['create', 'read']
- }
- ]
- }
- }
-)
-```
-
-
-
-
- ```rust wrap
- use open_payments::types::{AccessTokenRequest, AccessItem, QuoteAction, GrantRequest};
- let quote_access = AccessTokenRequest {
- access: vec![AccessItem::Quote { actions: vec![QuoteAction::Create] }],
- };
- let customer_grant_request = GrantRequest::new(quote_access, None);
- let customer_quote_grant = client
- .grant()
- .request(&customer_wallet_address.auth_server, &customer_grant_request)
- .await?;
- ```
-
-
-
-
-
-```php wrap
-$customerQuoteGrant = $client->grant()->request(
- [
- 'url' => $customerWalletAddress->authServer
- ],
- [
- 'access_token' => [
- 'access' => [
- [
- 'type' => 'quote',
- 'actions' => ['create']
- ]
- ]
- ]
- ]
-);
-```
-
-
-
-
-
-```go wrap
-quoteAccess := as.AccessQuote{
- Type: as.Quote,
- Actions: []as.AccessQuoteActions{as.Create},
-}
-quoteAccessItem := as.AccessItem{}
-if err := quoteAccessItem.FromAccessQuote(quoteAccess); err != nil {
- log.Fatalf("Error creating AccessItem: %v\n", err)
-}
-quoteAccessToken := struct {
- Access as.Access `json:"access"`
-}{
- Access: []as.AccessItem{quoteAccessItem},
-}
-customerQuoteGrant, err := client.Grant.Request(context.TODO(), op.GrantRequestParams{
- URL: *customerWalletAddress.AuthServer,
- RequestBody: as.GrantRequestWithAccessToken{AccessToken: quoteAccessToken},
-})
-if err != nil {
- log.Fatalf("Error requesting quote grant: %v\n", err)
-}
-```
-
-
-
-
-
-```java wrap
-var customerQuoteGrant = client.auth().grant().quote(
- customerWalletAddress
-);
-```
-
-
-
+
Ejemplo de respuesta
@@ -715,160 +242,7 @@ Primero, solicitemos un recurso de cotización asociado con el comerciante. La s
Posteriormente, llame de nuevo a la Create Quote API y solicite un recurso de cotización asociado con la `id` del pago entrante de la plataforma.
-
-
-
-```ts wrap
-// Merchant
-const merchantQuote = await client.quote.create(
- {
- url: customerWalletAddress.resourceServer,
- accessToken: customerQuoteGrant.access_token.value
- },
- {
- method: 'ilp',
- walletAddress: customerWalletAddress.id,
- receiver: merchantIncomingPayment.id
- }
-)
-// Platform
-const platformQuote = await client.quote.create(
- {
- url: customerWalletAddress.resourceServer,
- accessToken: customerQuoteGrant.access_token.value
- },
- {
- method: 'ilp',
- walletAddress: customerWalletAddress.id,
- receiver: platformIncomingPayment.id
- }
-)
-```
-
-
-
-
-```rust wrap
-use open_payments::types::{QuoteRequest, QuoteMethod};
-let merchant_quote_request = QuoteRequest {
- method: QuoteMethod::Ilp,
- wallet_address: Some(customer_wallet_address.id.clone()),
- receiver: Some(merchant_incoming_payment.id.clone()),
- debit_amount: None,
- receive_amount: None,
-};
-let platform_quote_request = QuoteRequest {
- method: QuoteMethod::Ilp,
- wallet_address: Some(customer_wallet_address.id.clone()),
- receiver: Some(platform_incoming_payment.id.clone()),
- debit_amount: None,
- receive_amount: None,
-};
-let merchant_quote = client
- .quotes()
- .create(&customer_wallet_address.resource_server, &merchant_quote_request, Some(&customer_quote_grant.access_token.value))
- .await?;
-let platform_quote = client
- .quotes()
- .create(&customer_wallet_address.resource_server, &platform_quote_request, Some(&customer_quote_grant.access_token.value))
- .await?;
-```
-
-
-
-
-
-```php wrap
-// Merchant
-$merchantQuote = $client->quote()->create(
- [
- 'url' => $customerWalletAddress->resourceServer,
- 'accessToken' => $customerQuoteGrant->access_token->value
- ],
- [
- 'method' => 'ilp',
- 'walletAddress' => $customerWalletAddress->id,
- 'receiver' => $merchantIncomingPayment->id
- ]
-);
-// Platform
-$platformQuote = $client->quote()->create(
- [
- 'url' => $customerWalletAddress->resourceServer,
- 'accessToken' => $customerQuoteGrant->access_token->value
- ],
- [
- 'method' => 'ilp',
- 'walletAddress' => $customerWalletAddress->id,
- 'receiver' => $platformIncomingPayment->id
- ]
-);
-```
-
-
-
-
-
-```go wrap
-// Merchant
-merchantQuote, err := client.Quote.Create(context.TODO(), op.QuoteCreateParams{
- BaseURL: *customerWalletAddress.ResourceServer,
- AccessToken: customerQuoteGrant.AccessToken.Value,
- Payload: rs.CreateQuoteJSONBody0{
- WalletAddressSchema: *customerWalletAddress.Id,
- Receiver: *merchantIncomingPayment.Id,
- Method: "ilp",
- },
-})
-if err != nil {
- log.Fatalf("Error creating merchant quote: %v\n", err)
-}
-// Platform
-platformQuote, err := client.Quote.Create(context.TODO(), op.QuoteCreateParams{
- BaseURL: *customerWalletAddress.ResourceServer,
- AccessToken: customerQuoteGrant.AccessToken.Value,
- Payload: rs.CreateQuoteJSONBody0{
- WalletAddressSchema: *customerWalletAddress.Id,
- Receiver: *platformIncomingPayment.Id,
- Method: "ilp",
- },
-})
-if err != nil {
- log.Fatalf("Error creating platform quote: %v\n", err)
-}
-```
-
-
-
-
-
-```java wrap
-// Merchant quote
-var merchantQuote = client.quote().create(
- customerQuoteGrant.getAccess().getToken(),
- customerWalletAddress,
- merchantIncomingPayment,
- Optional.empty(),
- Optional.empty()
-);
-
-// Platform quote
-var platformQuote = client.quote().create(
- customerQuoteGrant.getAccess().getToken(),
- customerWalletAddress,
- platformIncomingPayment,
- Optional.empty(),
- Optional.empty()
-);
-```
-
-
-
-
-Cada respuesta devuelve un `receiveAmount`, un `debitAmount` y demás información requerida.
-
-- `receiveAmount`: el valor del `incomingAmount` del recurso de pago entrante.
-- `debitAmount`: el monto que el consumidor debe pagar al recurso de pago entrante (el `receiveAmount` más cualquier tarifa que corresponda).
+
Ejemplo de respuesta
@@ -897,6 +271,11 @@ El siguiente ejemplo muestra una respuesta del proveedor de billetera del comerc
+Cada respuesta devuelve un `receiveAmount`, un `debitAmount` y demás información requerida.
+
+- `receiveAmount`: el valor del `incomingAmount` del recurso de pago entrante.
+- `debitAmount`: el monto que el consumidor debe pagar al recurso de pago entrante (el `receiveAmount` más cualquier tarifa que corresponda).
+
### 6. Solicitar una concesión de autorización interactiva para un pago saliente
Utilice la información del consumidor `authServer` recibida en el paso 1 para llamar a la [Grant Request API](/es/apis/auth-server/operations/post-request).
@@ -905,211 +284,6 @@ El propósito de esta llamada consiste en obtener un token de acceso que permita
-
-
-
- ```ts wrap
- const pendingCustomerOutgoingPaymentGrant = await client.grant.request(
- {
- url: customerWalletAddress.authServer
- },
- {
- access_token: {
- access: [
- {
- identifier: customerWalletAddress.id,
- type: 'outgoing-payment',
- actions: ['read', 'create'],
- limits: {
- receiveAmount: {
- assetCode: 'USD',
- assetScale: 2,
- value: '10000'
- }
- }
- }
- ]
- },
- interact: {
- start: ['redirect'],
- finish: {
- method: 'redirect',
- uri: 'http://localhost:3344',
- nonce: NONCE
- }
- }
- }
- )
- ```
-
-
-
-
-```rust wrap
-use open_payments::types::{AccessTokenRequest, AccessItem, OutgoingPaymentAction, InteractRequest, InteractStart, InteractFinish, InteractFinishMethod, AccessLimits, Amount, GrantRequest};
-
-let merchant_amount = match merchant_quote.debit_amount.as_ref() {
- Some(a) => &a.value,
- None => {
- eprintln!("Missing debit_amount on merchant quote");
- return Ok(());
- }
-};
-let platform_amount = match platform_quote.debit_amount.as_ref() {
- Some(a) => &a.value,
- None => {
- eprintln!("Missing debit_amount on platform quote");
- return Ok(());
- }
-};
-let merchant_value = match merchant_amount.parse::() {
- Ok(v) => v,
- Err(_) => {
- eprintln!("Invalid merchant debit_amount value");
- return Ok(());
- }
-};
-let platform_value = match platform_amount.parse::() {
- Ok(v) => v,
- Err(_) => {
- eprintln!("Invalid platform debit_amount value");
- return Ok(());
- }
-};
-let combined_quote_amount = merchant_value + platform_value;
-let outgoing_access = AccessTokenRequest {
- access: vec![AccessItem::OutgoingPayment {
- identifier: Some(customer_wallet_address.id.clone()),
- actions: vec![OutgoingPaymentAction::Create],
- limits: Some(AccessLimits { debit_amount: Some(Amount { value: combined_quote_amount.to_string(), asset_code: "USD".into(), asset_scale: 2 }), ..Default::default() }),
- }],
-};
-let interact = InteractRequest { start: Some(vec![InteractStart::Redirect]), finish: Some(InteractFinish { method: InteractFinishMethod::Redirect, uri: Some("https://paymentplatform.example/finish/{...}".into()), nonce: Some("NONCE".into()) }) };
-let outgoing_grant_request = GrantRequest::new(outgoing_access, Some(interact));
-let pending_customer_outgoing_payment_grant = client
- .grant()
- .request(&customer_wallet_address.auth_server, &outgoing_grant_request)
- .await?;
-```
-
-
-
-
- ```php wrap
- $combinedQuoteAmount = bcadd($merchantQuote->debitAmount->value, $platformQuote->debitAmount->value);
-
- $pendingCustomerOutgoingPaymentGrant = $client->grant()->request(
- [
- 'url' => $customerWalletAddress->authServer
- ],
- [
- 'access_token' => [
- 'access' => [
- [
- 'identifier' => $customerWalletAddress->id,
- 'type' => 'outgoing-payment',
- 'actions' => ['create'],
- 'limits' => [
- 'debitAmount' => [
- 'assetCode' => 'USD',
- 'assetScale' => 2,
- 'value' => $combinedQuoteAmount
- ]
- ]
- ]
- ]
- ],
- 'interact' => [
- 'start' => ['redirect'],
- 'finish' => [
- 'method' => 'redirect',
- 'uri' => 'https://paymentplatform.example/finish/{...}', // where to redirect the customer after they've completed interaction
- 'nonce' => 'NONCE'
- ]
- ]
- ]
- );
- ```
-
-
-
-
-
-```go wrap
-combinedQuoteAmount := "10000" // merchantQuote.DebitAmount.Value + platformQuote.DebitAmount.Value
-limits := as.LimitsOutgoing{}
-if err := limits.FromLimitsOutgoing1(as.LimitsOutgoing1{
- DebitAmount: as.Amount{
- Value: combinedQuoteAmount,
- AssetCode: "USD",
- AssetScale: 2,
- },
-}); err != nil {
- log.Fatalf("Error creating limits: %v\n", err)
-}
-outgoingAccess := as.AccessOutgoing{
- Type: as.OutgoingPayment,
- Actions: []as.AccessOutgoingActions{as.AccessOutgoingActionsCreate},
- Identifier: *customerWalletAddress.Id,
- Limits: &limits,
-}
-outgoingAccessItem := as.AccessItem{}
-if err := outgoingAccessItem.FromAccessOutgoing(outgoingAccess); err != nil {
- log.Fatalf("Error creating AccessItem: %v\n", err)
-}
-outgoingAccessToken := struct {
- Access as.Access `json:"access"`
-}{
- Access: []as.AccessItem{outgoingAccessItem},
-}
-interact := &as.InteractRequest{
- Start: []as.InteractRequestStart{as.InteractRequestStartRedirect},
- Finish: &as.InteractRequestFinish{
- Method: as.Redirect,
- Uri: "https://paymentplatform.example/finish/{...}", // where to redirect the customer after they've completed interaction
- Nonce: NONCE,
- },
-}
-pendingCustomerOutgoingPaymentGrant, err := client.Grant.Request(context.TODO(), op.GrantRequestParams{
- URL: *customerWalletAddress.AuthServer,
- RequestBody: as.GrantRequestWithAccessToken{
- AccessToken: outgoingAccessToken,
- Interact: interact,
- },
-})
-if err != nil {
- log.Fatalf("Error requesting outgoing payment grant: %v\n", err)
-}
-```
-
-
-
-
-
-```java wrap
-var merchantDebit = new BigDecimal(merchantQuote.getDebitAmount().getValue());
-var platformDebit = new BigDecimal(platformQuote.getDebitAmount().getValue());
-var combinedQuoteAmount = merchantDebit.add(platformDebit);
-
-var debitAmount = Amount.build(
- combinedQuoteAmount,
- merchantQuote.getDebitAmount().getAssetCode(),
- merchantQuote.getDebitAmount().getAssetScale()
-);
-
-var urlToOpen = "https://paymentplatform.example/finish/{...}";
-
-var opContinueInteract = client.auth().grant().continuation(
- customerWalletAddress,
- debitAmount,
- URI.create(urlToOpen),
- "NONCE"
-);
-```
-
-
-
-
Ejemplo de respuesta
@@ -1131,6 +305,7 @@ var opContinueInteract = client.auth().grant().continuation(
+
### 7. Comenzar la interacción con el consumidor
@@ -1155,79 +330,7 @@ Emita la solicitud al `continue uri` proporcionado en la respuesta de concesión
Incluya la `interact_ref` devuelta en los parámetros de consulta del URI de redirección.
-
-
-
-```ts wrap
-const customerOutgoingPaymentGrant = await client.grant.continue(
- {
- url: pendingCustomerOutgoingPaymentGrant.continue.uri,
- accessToken: pendingCustomerOutgoingPaymentGrant.continue.access_token.value
- },
- {
- interact_ref: interactRef
- }
-)
-```
-
-
-
-
-```rust wrap
-let customer_outgoing_payment_grant = client
- .grant()
- .continue_grant(
- if let Some(continue_field) = &pending_customer_outgoing_payment_grant.continue_field { &continue_field.uri } else { eprintln!("Missing continue field on pending grant"); return Ok(()); },
- &interact_ref,
- if let Some(continue_field) = &pending_customer_outgoing_payment_grant.continue_field { Some(&continue_field.access_token.value) } else { None },
- )
- .await?;
-```
-
-
-
-
-
-```php wrap
-$customerOutgoingPaymentGrant = $client->grant()->continue(
- [
- 'url' => $pendingCustomerOutgoingPaymentGrant->continue->uri,
- 'accessToken' => $pendingCustomerOutgoingPaymentGrant->continue->access_token->value
- ],
- [
- 'interact_ref' => $interactRef
- ]
-);
-```
-
-
-
-
-
-```go wrap
-customerOutgoingPaymentGrant, err := client.Grant.Continue(context.TODO(), op.GrantContinueParams{
- URL: pendingCustomerOutgoingPaymentGrant.Continue.Uri,
- AccessToken: pendingCustomerOutgoingPaymentGrant.Continue.AccessToken.Value,
- InteractRef: INTERACT_REF
-})
-if err != nil {
- log.Fatalf("Error continuing grant: %v\n", err)
-}
-```
-
-
-
-
-
-```java wrap
-var customerOutgoingPaymentGrant = client.auth().grant().finalize(
- opContinueInteract,
- interactRef
-);
-```
-
-
-
+
Ejemplo de respuesta
@@ -1258,6 +361,7 @@ var customerOutgoingPaymentGrant = client.auth().grant().finalize(
```
+
### 10. Solicitar la creación de recursos de pagos salientes
Recuerde que las respuestas de la Create Quote API para el comerciante y para su plataforma (paso 5) incluían un `debitAmount` y un `receiveAmount`. Las respuestas también incluían una `id`, que es una URL para identificar cada cotización.
@@ -1268,153 +372,7 @@ Utilice los tókenes de acceso devueltos en el paso 5 para llamar a la
-
-
- ```ts wrap
- // Merchant
- const customerOutgoingPaymentToMerchant = await client.outgoingPayment.create(
- {
- url: customerWalletAddress.resourceServer,
- accessToken: customerOutgoingPaymentGrant.access_token.value
- },
- {
- walletAddress: customerWalletAddress.id,
- quoteId: merchantQuote.id
- }
- )
- // Platform
- const customerOutgoingPaymentToPlatform = await client.outgoingPayment.create(
- {
- url: customerWalletAddress.resourceServer,
- accessToken: customerOutgoingPaymentGrant.access_token.value
- },
- {
- walletAddress: customerWalletAddress.id,
- quoteId: platformQuote.id
- }
- )
- ```
-
-
-
-
-```rust wrap
-use open_payments::types::OutgoingPaymentRequest;
-let merchant_outgoing_request = OutgoingPaymentRequest {
- wallet_address: customer_wallet_address.id.clone(),
- receiver: Some(merchant_incoming_payment.id.clone()),
- debit_amount: None,
- receive_amount: None,
- quote_id: Some(merchant_quote.id.clone()),
-};
-let platform_outgoing_request = OutgoingPaymentRequest {
- wallet_address: customer_wallet_address.id.clone(),
- receiver: Some(platform_incoming_payment.id.clone()),
- debit_amount: None,
- receive_amount: None,
- quote_id: Some(platform_quote.id.clone()),
-};
-let customer_outgoing_payment_to_merchant = client
- .outgoing_payments()
- .create(&customer_wallet_address.resource_server, &merchant_outgoing_request, Some(&customer_outgoing_payment_grant.access_token.value))
- .await?;
-let customer_outgoing_payment_to_platform = client
- .outgoing_payments()
- .create(&customer_wallet_address.resource_server, &platform_outgoing_request, Some(&customer_outgoing_payment_grant.access_token.value))
- .await?;
-```
-
-
-
-
-
- ```php wrap
- // Merchant
- $customerOutgoingPaymentToMerchant = $client->outgoingPayment()->create(
- [
- 'url' => $customerWalletAddress->resourceServer,
- 'accessToken' => $customerOutgoingPaymentGrant->access_token->value
- ],
- [
- 'walletAddress' => $customerWalletAddress->id,
- 'quoteId' => $merchantQuote->id
- ]
- );
- // Platform
- $customerOutgoingPaymentToPlatform = $client->outgoingPayment()->create(
- [
- 'url' => $customerWalletAddress->resourceServer,
- 'accessToken' => $customerOutgoingPaymentGrant->access_token->value
- ],
- [
- 'walletAddress' => $customerWalletAddress->id,
- 'quoteId' => $platformQuote->id
- ]
- );
- ```
-
-
-
-
-
- ```go wrap
- // Merchant
- var merchantOutgoingPayload rs.CreateOutgoingPaymentRequest
- if err := merchantOutgoingPayload.FromCreateOutgoingPaymentWithQuote(rs.CreateOutgoingPaymentWithQuote{
- WalletAddressSchema: *customerWalletAddress.Id,
- QuoteId: *merchantQuote.Id,
- }); err != nil {
- log.Fatalf("Error creating merchant payload: %v\n", err)
- }
- customerOutgoingPaymentToMerchant, err := client.OutgoingPayment.Create(context.TODO(), op.OutgoingPaymentCreateParams{
- BaseURL: *customerWalletAddress.ResourceServer,
- AccessToken: customerOutgoingPaymentGrant.AccessToken.Value,
- Payload: merchantOutgoingPayload,
- })
- if err != nil {
- log.Fatalf("Error creating outgoing payment to merchant: %v\n", err)
- }
- // Platform
- var platformOutgoingPayload rs.CreateOutgoingPaymentRequest
- if err := platformOutgoingPayload.FromCreateOutgoingPaymentWithQuote(rs.CreateOutgoingPaymentWithQuote{
- WalletAddressSchema: *customerWalletAddress.Id,
- QuoteId: *platformQuote.Id,
- }); err != nil {
- log.Fatalf("Error creating platform payload: %v\n", err)
- }
- customerOutgoingPaymentToPlatform, err := client.OutgoingPayment.Create(context.TODO(), op.OutgoingPaymentCreateParams{
- BaseURL: *customerWalletAddress.ResourceServer,
- AccessToken: customerOutgoingPaymentGrant.AccessToken.Value,
- Payload: platformOutgoingPayload,
- })
- if err != nil {
- log.Fatalf("Error creating outgoing payment to platform: %v\n", err)
- }
- ```
-
-
-
-
-
-```java wrap
-// Merchant
-var customerOutgoingPaymentToMerchant = client.payment().createOutgoing(
- customerOutgoingPaymentGrant,
- customerWalletAddress,
- merchantQuote
-);
-
-// Platform
-var customerOutgoingPaymentToPlatform = client.payment().createOutgoing(
- customerOutgoingPaymentGrant,
- customerWalletAddress,
- platformQuote
-);
-```
-
-
-
+
Ejemplo de respuesta
diff --git a/docs/src/content/docs/guides/accept-otp-online-purchase.mdx b/docs/src/content/docs/guides/accept-otp-online-purchase.mdx
index 34ed0c7a..8dd2fac6 100644
--- a/docs/src/content/docs/guides/accept-otp-online-purchase.mdx
+++ b/docs/src/content/docs/guides/accept-otp-online-purchase.mdx
@@ -6,6 +6,14 @@ import { LinkOut } from '@interledger/docs-design-system'
import { Tabs, TabItem, Badge } from '@astrojs/starlight/components'
import Start from '/src/content/docs/partials/_grant-start-interaction.mdx'
import Finish from '/src/content/docs/partials/_grant-finish-interaction.mdx'
+import GetWalletAddress from '/src/content/docs/partials/code/guides/accept-otp-online-purchase/_get-wallet-address.mdx'
+import GrantRequestIncomingPayment from '/src/content/docs/partials/code/guides/accept-otp-online-purchase/_grant-request-incoming-payment.mdx'
+import CreateIncomingPayment from '/src/content/docs/partials/code/guides/accept-otp-online-purchase/_create-incoming-payment.mdx'
+import GrantRequestQuote from '/src/content/docs/partials/code/guides/accept-otp-online-purchase/_grant-request-quote.mdx'
+import CreateQuote from '/src/content/docs/partials/code/guides/accept-otp-online-purchase/_create-quote.mdx'
+import GrantRequestOutgoingPayment from '/src/content/docs/partials/code/guides/accept-otp-online-purchase/_grant-request-outgoing-payment.mdx'
+import CreateOutgoingPayment from '/src/content/docs/partials/code/guides/accept-otp-online-purchase/_create-outgoing-payment.mdx'
+import GrantContinuationRequest from '/src/content/docs/partials/code/guides/accept-otp-online-purchase/_grant-continuation-request.mdx'
:::tip[Summary]
Learn how to accept a one-time payment of an agreed-upon amount.
@@ -63,79 +71,7 @@ Let's assume the customer entered their wallet address into the site's checkout
Call the [Get Wallet Address API](/apis/wallet-address-server/operations/get-wallet-address) for each address.
-
-
-
-```ts wrap
-const customerWalletAddress = await client.walletAddress.get({
- url: 'https://cloudninebank.example.com/customer'
-})
-const retailerWalletAddress = await client.walletAddress.get({
- url: 'https://happylifebank.example.com/retailer'
-})
-```
-
-
-
-
-```rust wrap
-let sender_wallet_address = client.wallet_address().get("https://cloudninebank.example.com/customer").await?;
-let retailer_wallet_address = client.wallet_address().get("https://happylifebank.example.com/retailer").await?;
-```
-
-
-
-```php
-$customerWalletAddress = $client->walletAddress()->get([
- 'url' => 'https://cloudninebank.example.com/customer'
-]);
-$retailerWalletAddress = $client->walletAddress()->get([
- 'url' => 'https://happylifebank.example.com/retailer'
-]);
-```
-
-
-
-
-
-```go wrap
-customerWalletAddress, err := client.WalletAddress.Get(context.TODO(), op.WalletAddressGetParams{
- URL: "https://cloudninebank.example.com/customer",
-})
-if err != nil {
- log.Fatalf("Error fetching customer wallet address: %v\n", err)
-}
-
-retailerWalletAddress, err := client.WalletAddress.Get(context.TODO(), op.WalletAddressGetParams{
- URL: "https://happylifebank.example.com/retailer",
-})
-if err != nil {
- log.Fatalf("Error fetching retailer wallet address: %v\n", err)
-}
-
-```
-
-
-
-
-
-```java wrap
-var customerWalletAddress = client.walletAddress().get("https://cloudninebank.example.com/customer");
-var retailerWalletAddress = client.walletAddress().get("https://happylifebank.example.com/retailer");
-```
-
-
-
-
-
-```csharp wrap
-var customerWalletAddress = await client.GetWalletAddressAsync("https://cloudninebank.example.com/customer");
-var retailerWalletAddress = await client.GetWalletAddressAsync("https://happylifebank.example.com/retailer");
-```
-
-
-
-
+
Example response
@@ -160,133 +96,7 @@ Use the retailer's `authServer` details, received in the previous step, to call
This call obtains an access token that allows the client app to request an incoming payment resource be created on the retailer's wallet account.
-
-
-
-```ts wrap
-const retailerIncomingPaymentGrant = await client.grant.request(
- {
- url: retailerWalletAddress.authServer
- },
- {
- access_token: {
- access: [
- {
- type: 'incoming-payment',
- actions: ['create']
- }
- ]
- }
- }
-)
-```
-
-
-
-
-```rust wrap
-use open_payments::types::{AccessTokenRequest, AccessItem, IncomingPaymentAction, GrantRequest};
-
-let incoming_access = AccessTokenRequest {
-access: vec![AccessItem::IncomingPayment { actions: vec![IncomingPaymentAction::Create], identifier: None }],
-};
-let incoming_grant_request = GrantRequest::new(incoming_access, None);
-
-let retailer_incoming_payment_grant = client
-.grant()
-.request(&retailer_wallet_address.auth_server, &incoming_grant_request)
-.await?;
-
-```
-
-
-
-
-
-```php
-$retailerIncomingPaymentGrant = $client->grant()->request(
- [
- 'url' => $retailerWalletAddress->authServer
- ],
- [
- 'access_token' => [
- 'access' => [
- [
- 'type' => 'incoming-payment',
- 'actions' => ['create']
- ]
- ]
- ]
- ]
-);
-```
-
-
-
-
-
-```go wrap
-incomingAccess := as.AccessIncoming{
- Type: as.IncomingPayment,
- Actions: []as.AccessIncomingActions{as.AccessIncomingActionsCreate},
-}
-accessItem := as.AccessItem{}
-if err := accessItem.FromAccessIncoming(incomingAccess); err != nil {
- log.Fatalf("Error creating AccessItem: %v\n", err)
-}
-accessToken := struct {
- Access as.Access `json:"access"`
-}{
- Access: []as.AccessItem{accessItem},
-}
-
-retailerIncomingPaymentGrant, err := client.Grant.Request(context.TODO(), op.GrantRequestParams{
- URL: *retailerWalletAddress.AuthServer,
- RequestBody: as.GrantRequestWithAccessToken{AccessToken: accessToken},
-})
-if err != nil {
- log.Fatalf("Error requesting incoming payment grant: %v\n", err)
-}
-```
-
-
-
-
-
-```java wrap
-var retailerIncomingPaymentGrant = client.auth().grant().incomingPayment(
- retailerWalletAddress
-);
-```
-
-
-
-
-
-```csharp wrap
-var retailerIncomingPaymentGrant = await client.RequestGrantAsync(
- new RequestArgs
- {
- Url = retailerWalletAddress.AuthServer,
- },
- new GrantCreateBody
- {
- AccessToken = new AccessToken
- {
- Access =
- [
- new IncomingAccess
- {
- Actions = [Actions.Create]
- }
- ]
- }
- }
-);
-```
-
-
-
+
Example response
@@ -324,125 +134,7 @@ This call requests an incoming payment resource be created on the retailer's wal
Remember that the full amount of the customer's purchase is $1,400 MXN.
-
-
-
-```ts wrap
-const retailerIncomingPayment = await.client.incomingPayment.create(
- {
- url: retailerWalletAddress.resourceServer,
- accessToken: retailerIncomingPaymentGrant.access_token.value
- },
- {
- walletAddress: retailerWalletAddress.id,
- incomingAmount: {
- value: '140000',
- assetCode: 'MXN',
- assetScale: 2
- }
- }
-)
-```
-
-
-
-
-```rust wrap
-use open_payments::types::{IncomingPaymentRequest, Amount};
-
-let incoming_request = IncomingPaymentRequest {
-wallet_address: retailer_wallet_address.id.clone(),
-incoming_amount: Some(Amount { value: "140000".into(), asset_code: "MXN".into(), asset_scale: 2 }),
-expires_at: None,
-metadata: None,
-};
-
-let retailer_incoming_payment = client
-.incoming_payments()
-.create(
-&retailer_wallet_address.resource_server,
-&incoming_request,
-Some(&retailer_incoming_payment_grant.access_token.value),
-)
-.await?;
-
-```
-
-
-
-
-
-```php
-$retailerIncomingPayment = $client->incomingPayment()->create(
- [
- 'url' => $retailerWalletAddress->resourceServer,
- 'accessToken' => $retailerIncomingPaymentGrant->access_token->value
- ],
- [
- 'walletAddress' => $retailerWalletAddress->id,
- 'incomingAmount' => [
- 'value' => '140000',
- 'assetCode' => 'MXN',
- 'assetScale' => 2
- ]
- ]
-);
-```
-
-
-
-
-```go wrap
-incomingPayment, err := client.IncomingPayment.Create(context.TODO(), op.IncomingPaymentCreateParams{
- BaseURL: *retailerWalletAddress.ResourceServer,
- AccessToken: retailerIncomingPaymentGrant.AccessToken.Value,
- Payload: rs.CreateIncomingPaymentJSONBody{
- WalletAddressSchema: *retailerWalletAddress.Id,
- IncomingAmount: &rs.Amount{
- Value: "140000",
- AssetCode: "MXN",
- AssetScale: 2,
- },
- },
-})
-if err != nil {
- log.Fatalf("Error creating incoming payment: %v\n", err)
-}
-```
-
-
-
-
-
-```java wrap
-var retailerIncomingPayment = client.payment().createIncoming(
- retailerWalletAddress,
- retailerIncomingPaymentGrant,
- BigDecimal.valueOf(1400.00)
-);
-```
-
-
-
-
-
-```csharp wrap
-var retailerIncomingPayment = await client.CreateIncomingPaymentAsync(
- new AuthRequestArgs
- {
- Url = retailerWalletAddress.ResourceServer,
- AccessToken = retailerIncomingPaymentGrant.AccessToken.Value
- },
- new IncomingPaymentBody
- {
- WalletAddress = retailerWalletAddress.Id,
- IncomingAmount = new Amount("140000", "MXN", 2)
- }
-);
-```
-
-
-
+
Example response
@@ -483,132 +175,7 @@ Use the customer's `authServer` details, returned in Step 1, to call the
-
-
-```ts wrap
-const customerQuoteGrant = await client.grant.request(
- {
- url: customerWalletAddress.authServer
- },
- {
- access_token: {
- access: [
- {
- type: 'quote',
- actions: ['create']
- }
- ]
- }
- }
-)
-```
-
-
-
-
-```rust wrap
-use open_payments::types::{AccessTokenRequest, AccessItem, QuoteAction, GrantRequest};
-
-let quote_access = AccessTokenRequest {
-access: vec![AccessItem::Quote { actions: vec![QuoteAction::Create] }],
-};
-let quote_grant_request = GrantRequest::new(quote_access, None);
-let customer_quote_grant = client
-.grant()
-.request(&customer_wallet_address.auth_server, "e_grant_request)
-.await?;
-
-```
-
-
-
-
-```php
-$customerQuoteGrant = $client->grant()->request(
- [
- 'url' => $customerWalletAddress->authServer
- ],
- [
- 'access_token' => [
- 'access' => [
- [
- 'type' => 'quote',
- 'actions' => ['create']
- ]
- ]
- ]
- ]
-);
-```
-
-
-
-
-
-```go wrap
-quoteAccess := as.AccessQuote{
- Type: as.Quote,
- Actions: []as.AccessQuoteActions{as.Create},
-}
-quoteAccessItem := as.AccessItem{}
-if err := quoteAccessItem.FromAccessQuote(quoteAccess); err != nil {
- log.Fatalf("Error creating AccessItem: %v\n", err)
-}
-quoteAccessToken := struct {
- Access as.Access `json:"access"`
-}{
- Access: []as.AccessItem{quoteAccessItem},
-}
-
-customerQuoteGrant, err := client.Grant.Request(context.TODO(), op.GrantRequestParams{
- URL: *customerWalletAddress.AuthServer,
- RequestBody: as.GrantRequestWithAccessToken{AccessToken: quoteAccessToken},
-})
-if err != nil {
- log.Fatalf("Error requesting quote grant: %v\n", err)
-}
-```
-
-
-
-
-
-```java wrap
-var customerQuoteGrant = client.auth().grant().quote(
- customerWalletAddress
-);
-```
-
-
-
-
-
-```csharp wrap
-var customerQuoteGrant = await client.RequestGrantAsync(
- new RequestArgs
- {
- Url = customerWalletAddress.AuthServer,
- },
- new GrantCreateBody
- {
- AccessToken = new AccessToken
- {
- Access =
- [
- new QuoteAccess
- {
- Actions = [Actions.Create]
- }
- ]
- }
- }
-);
-```
-
-
-
-
+
Example response
@@ -646,126 +213,7 @@ This call requests a quote resource be created on the customer's wallet account.
The request must contain the receiver, which is the `id` of the incoming payment. The `id` was returned in the Create an Incoming Payment API response in Step 3.
-
-
-
-```ts wrap
-const customerQuote = await client.quote.create(
- {
- url: customerWalletAddress.resourceServer,
- accessToken: customerQuoteGrant.access_token.value
- },
- {
- method: 'ilp',
- walletAddress: customerWalletAddress.id,
- receiver: retailerIncomingPayment.id
- }
-)
-```
-
-
-
-
-```rust wrap
-use open_payments::types::{QuoteRequest, QuoteMethod};
-
-let quote_request = QuoteRequest {
-method: QuoteMethod::Ilp,
-wallet_address: Some(customer_wallet_address.id.clone()),
-receiver: Some(retailer_incoming_payment.id.clone()),
-debit_amount: None,
-receive_amount: None,
-};
-
-let customer_quote = client
-.quotes()
-.create(
-&customer_wallet_address.resource_server,
-"e_request,
-Some(&customer_quote_grant.access_token.value),
-)
-.await?;
-
-```
-
-
-
-
-```php
-$customerQuote = $client->quote()->create(
- [
- 'url' => $customerWalletAddress->resourceServer,
- 'accessToken' => $customerQuoteGrant->access_token->value
- ],
- [
- 'method' => 'ilp',
- 'walletAddress' => $customerWalletAddress->id,
- 'receiver' => $retailerIncomingPayment->id
- ]
-);
-```
-
-
-
-
-
-```go wrap
-customerQuote, err := client.Quote.Create(context.TODO(), op.QuoteCreateParams{
- BaseURL: *customerWalletAddress.ResourceServer,
- AccessToken: customerQuoteGrant.AccessToken.Value,
- Payload: rs.CreateQuoteJSONBody0{
- WalletAddressSchema: *customerWalletAddress.Id,
- Receiver: *incomingPayment.Id,
- Method: "ilp",
- },
-})
-if err != nil {
- log.Fatalf("Error creating quote: %v\n", err)
-}
-```
-
-
-
-
-
-```java wrap
-var customerQuote = client.quote().create(
- customerQuoteGrant.getAccess().getToken(),
- customerWalletAddress,
- retailerIncomingPayment,
- Optional.empty(),
- Optional.empty()
-);
-```
-
-
-
-
-
-```csharp wrap
-var customerQuote = await client.CreateQuoteAsync(
- new AuthRequestArgs
- {
- Url = customerWalletAddress.ResourceServer,
- AccessToken = customerQuoteGrant.AccessToken.Value
- },
- new QuoteBody
- {
- WalletAddress = customerWalletAddress.Id,
- Receiver = retailerWalletAddress.Id,
- Method = PaymentMethod.Ilp
- }
-);
-```
-
-
-
-
-
-The response returns a `receiveAmount`, a `debitAmount`, and other required information.
-
-- `debitAmount` - The amount (in MXN) that will be charged to the customer
-- `receiveAmount` - The `incomingAmount` value from the incoming payment resource
+
Example response
@@ -794,6 +242,11 @@ The following is an example response from the customer's wallet provider.
+The response returns a `receiveAmount`, a `debitAmount`, and other required information.
+
+- `debitAmount` - The amount (in MXN) that will be charged to the customer
+- `receiveAmount` - The `incomingAmount` value from the incoming payment resource
+
### 6. Request an interactive outgoing payment grant
Use the customer's `authServer` information to call the [Grant Request API](/apis/auth-server/operations/post-request).
@@ -804,220 +257,7 @@ This call obtains an access token that allows the client app to request outgoing
Outgoing payments require an interactive grant. This type of grant will obtain the customer's consent before an outgoing payment is made against their wallet account. You can find more information in the [Open Payments flow](/concepts/op-flow/#outgoing-payment) and [identity providers](/identity/idp) pages.
:::
-
-
-
-```ts wrap
-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
- }
- }
- }
-)
-```
-
-
-
-
-```rust wrap
-use open_payments::types::{AccessTokenRequest, AccessItem, OutgoingPaymentAction, InteractRequest, InteractStart, InteractFinish, InteractFinishMethod, AccessLimits, Amount, GrantRequest};
-
-let access_limits = AccessLimits {
- debit_amount: Some(Amount { value: "140000".into(), asset_code: "MXN".into(), asset_scale: 2 }),
- ..Default::default()
-};
-let access_request = AccessTokenRequest {
- access: vec![AccessItem::OutgoingPayment {
- identifier: Some(customer_wallet_address.id.clone()),
- actions: vec![OutgoingPaymentAction::Create],
- limits: Some(access_limits),
- }],
-};
-let interact_request = InteractRequest {
- start: Some(vec![InteractStart::Redirect]),
- finish: Some(InteractFinish {
- method: InteractFinishMethod::Redirect,
- uri: Some("https://paymentplatform.example/finish/{...}".into()),
- nonce: Some("NONCE".into()),
- }),
-};
-
-let grant_request = GrantRequest::new(access_request, Some(interact_request));
-let pending_customer_outgoing_payment_grant = client
- .grant()
- .request(&customer_wallet_address.auth_server, &grant_request)
- .await?;
-```
-
-
-
-
-```php
-$pendingCustomerOutgoingPaymentGrant = $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'
- ]
- ]
- ]
-);
-```
-
-
-
-
-
-```go wrap
-outgoingAccess := as.AccessOutgoing{
- Type: as.OutgoingPayment,
- Actions: []as.AccessOutgoingActions{as.AccessOutgoingActionsCreate},
- Identifier: *customerWalletAddress.Id,
- Limits: &as.LimitsOutgoing{
- DebitAmount: &as.Amount{
- Value: "140000",
- AssetCode: "MXN",
- AssetScale: 2,
- },
- },
-}
-outgoingAccessItem := as.AccessItem{}
-if err := outgoingAccessItem.FromAccessOutgoing(outgoingAccess); err != nil {
- log.Fatalf("Error creating AccessItem: %v\n", err)
-}
-outgoingAccessToken := struct {
- Access as.Access `json:"access"`
-}{
- Access: []as.AccessItem{outgoingAccessItem},
-}
-interact := &as.InteractRequest{
- Start: []as.InteractRequestStart{as.InteractRequestStartRedirect},
- Finish: &as.InteractRequestFinish{
- Method: as.Redirect,
- Uri: "https://paymentplatform.example/finish/{...}",
- Nonce: NONCE,
- },
-}
-
-pendingCustomerOutgoingPaymentGrant, err := client.Grant.Request(context.TODO(), op.GrantRequestParams{
- URL: *customerWalletAddress.AuthServer,
- RequestBody: as.GrantRequestWithAccessToken{
- AccessToken: outgoingAccessToken,
- Interact: interact,
- },
-})
-
-if err != nil {
- log.Fatalf("Error requesting outgoing payment grant: %v\n", err)
-}
-```
-
-
-
-
-
-```java wrap
-var urlToOpen = "https://paymentplatform.example/finish/{...}";
-
-var opContinueInteract = client.auth().grant().continuation(
- customerWalletAddress,
- customerQuote.getDebitAmount(),
- URI.create(urlToOpen),
- "NONCE"
-);
-```
-
-
-
-
-
-```csharp wrap
-var pendingCustomerOutgoingPaymentGrant = await client.RequestGrantAsync(
- new RequestArgs
- {
- Url = customerWalletAddress.AuthServer,
- },
- new GrantCreateBodyWithInteract
- {
- AccessToken = new AccessToken
- {
- Access =
- [
- new OutgoingAccess
- {
- Identifier = customerWalletAddress.Id,
- Actions = [Actions.Create],
- Limits = new OutgoingAccessLimits
- {
- DebitAmount = new AuthAmount("140000", "MXN", 2)
- }
- }
- ]
- },
- Interact = new InteractRequest
- {
- Start = [Start.Redirect],
- Finish = new Finish
- {
- Method = FinishMethod.Redirect,
- Uri = new Uri("https://localhost"),
- Nonce = NONCE
- }
- }
- }
-);
-```
-
-
-
-
+
Example response
@@ -1064,107 +304,7 @@ Issue the request to the `continue.uri` provided in the initial outgoing payment
Include the `interact_ref` returned in the redirect URI's query parameters.
-
-
-
-```ts wrap
-const customerOutgoingPaymentGrant = await client.grant.continue(
- {
- url: pendingCustomerOutgoingPaymentGrant.continue.uri,
- accessToken: pendingCustomerOutgoingPaymentGrant.continue.access_token.value
- },
- {
- interact_ref: interactRef
- }
-)
-```
-
-
-
-
-```rust wrap
-let continue_field = match &pending_customer_outgoing_payment_grant.continue_field {
- Some(c) => c,
- None => {
- eprintln!("Missing continue field on pending grant");
- return Ok(());
- }
-};
-
-let customer_outgoing_payment_grant = client
-.grant()
-.continue_grant(
-&continue_field.uri,
-&interact_ref,
-Some(&continue_field.access_token.value),
-)
-.await?;
-
-```
-
-
-
-
-
-```php
-$customerOutgoingPaymentGrant = $client->grant()->continue(
- [
- 'url' => $pendingCustomerOutgoingPaymentGrant->continue->uri,
- 'accessToken' => $pendingCustomerOutgoingPaymentGrant->continue->access_token->value
- ],
- [
- 'interact_ref' => $interactRef
- ]
-);
-```
-
-
-
-
-
-```go wrap
-customerOutgoingPaymentGrant, err := client.Grant.Continue(context.TODO(), op.GrantContinueParams{
- URL: pendingCustomerOutgoingPaymentGrant.Continue.Uri,
- AccessToken: pendingCustomerOutgoingPaymentGrant.Continue.AccessToken.Value,
- InteractRef: INTERACT_REF,
-})
-if err != nil {
- log.Fatalf("Error continuing grant: %v\n", err)
-}
-```
-
-
-
-
-
-```java wrap
-var customerOutgoingPaymentGrant = client.auth().grant().finalize(
- opContinueInteract,
- interactRef
-);
-```
-
-
-
-
-
-```csharp wrap
-var customerOutgoingPaymentGrant = await client.ContinueGrantAsync(
- new AuthRequestArgs
- {
- Url = pendingCustomerOutgoingPaymentGrant.Continue.Uri,
- AccessToken = pendingCustomerOutgoingPaymentGrant.Continue.AccessToken.Value
- },
- new GrantContinueBody
- {
- InteractRef = interactRef
- }
-);
-```
-
-
-
-
+
Example response
@@ -1202,120 +342,7 @@ The following is an example response from the customer's wallet provider.
Use the access token returned in Step 9 to call the [Create Outgoing Payment API](/apis/resource-server/operations/create-outgoing-payment/). This call requests the creation of an outgoing payment resource be created on the customer's wallet account. Include the `quoteId` in the request. The `quoteId` is the `id` returned in the Create Quote API response (Step 5).
-
-
-
-```ts wrap
-const customerOutgoingPayment = await client.outgoingPayment.create(
- {
- url: customerWalletAddress.resourceServer,
- accessToken: customerOutgoingPaymentGrant.access_token.value
- },
- {
- walletAddress: customerWalletAddress.id,
- quoteId: customerQuote.id
- }
-)
-```
-
-
-
-
-```rust wrap
-use open_payments::types::OutgoingPaymentRequest;
-let outgoing_request = OutgoingPaymentRequest {
- wallet_address: customer_wallet_address.id.clone(),
- receiver: Some(retailer_incoming_payment.id.clone()),
- debit_amount: None,
- receive_amount: None,
- quote_id: Some(customer_quote.id.clone()),
-};
-let customer_outgoing_payment_to_retailer = client
- .outgoing_payments()
- .create(
- &customer_wallet_address.resource_server,
- &outgoing_request,
- Some(&customer_outgoing_payment_grant.access_token.value),
- )
- .await?;
-```
-
-
-
-
-
-```php
-$customerOutgoingPayment = $client->outgoingPayment()->create(
- [
- 'url' => $customerWalletAddress->resourceServer,
- 'accessToken' => $customerOutgoingPaymentGrant->access_token->value
- ],
- [
- 'walletAddress' => $customerWalletAddress->id,
- 'quoteId' => $customerQuote->id
- ]
-);
-```
-
-
-
-
-
-```go
-var outgoingPayload rs.CreateOutgoingPaymentRequest
-if err := outgoingPayload.FromCreateOutgoingPaymentWithQuote(rs.CreateOutgoingPaymentWithQuote{
- WalletAddressSchema: *customerWalletAddress.Id,
- QuoteId: *customerQuote.Id,
-}); err != nil {
- log.Fatalf("Error creating payload: %v\n", err)
-}
-
-customerOutgoingPayment, err := client.OutgoingPayment.Create(context.TODO(), op.OutgoingPaymentCreateParams{
- BaseURL: customerWalletAddress.ResourceServer,
- AccessToken: customerOutgoingPaymentGrant.AccessToken.Value,
- Payload: outgoingPayload
-})
-if err != nil {
- log.Fatalf("Error creating outgoing payment: %v\n", err)
-}
-```
-
-
-
-
-
-```java wrap
-var customerOutgoingPayment = client.payment().createOutgoing(
- customerOutgoingPaymentGrant,
- customerWalletAddress,
- customerQuote
-);
-```
-
-
-
-
-
-```csharp wrap
-var customerOutgoingPayment = await client.CreateOutgoingPaymentAsync(
- new AuthRequestArgs
- {
- Url = customerWalletAddress.ResourceServer,
- AccessToken = customerOutgoingPaymentGrant.AccessToken.Value
- },
- new OutgoingPaymentBodyFromQuote
- {
- WalletAddress = customerWalletAddress.Id,
- QuoteId = customerQuote.Id,
- }
-);
-```
-
-
-
-
-
-If the request fails because of an expired quote, [request a new quote](#5-request-the-creation-of-a-quote-resource) and try again.
+
Example response
@@ -1348,6 +375,7 @@ The following is an example response from the customer's wallet provider.
+If the request fails because of an expired quote, [request a new quote](#5-request-the-creation-of-a-quote-resource) and try again.
:::note[Access token expiry]
If a grant's access token has expired, call the [Rotate Access Token API](/apis/auth-server/operations/post-token/), then use the new token in the appropriate request.
:::
diff --git a/docs/src/content/docs/guides/onetime-remittance-fixed-debit.mdx b/docs/src/content/docs/guides/onetime-remittance-fixed-debit.mdx
index 15a8fae8..c5373f79 100644
--- a/docs/src/content/docs/guides/onetime-remittance-fixed-debit.mdx
+++ b/docs/src/content/docs/guides/onetime-remittance-fixed-debit.mdx
@@ -6,6 +6,14 @@ import { LinkOut } from '@interledger/docs-design-system'
import { Tabs, TabItem, Badge } from '@astrojs/starlight/components'
import Start from '/src/content/docs/partials/_grant-start-interaction.mdx'
import Finish from '/src/content/docs/partials/_grant-finish-interaction.mdx'
+import GetWalletAddress from '/src/content/docs/partials/code/guides/onetime-remittance-fixed-debit/_get-wallet-address.mdx'
+import GrantRequestIncomingPayment from '/src/content/docs/partials/code/guides/onetime-remittance-fixed-debit/_grant-request-incoming-payment.mdx'
+import CreateIncomingPaymentOpen from '/src/content/docs/partials/code/guides/onetime-remittance-fixed-debit/_create-incoming-payment-open.mdx'
+import GrantRequestQuote from '/src/content/docs/partials/code/guides/onetime-remittance-fixed-debit/_grant-request-quote.mdx'
+import CreateQuoteDebitAmount from '/src/content/docs/partials/code/guides/onetime-remittance-fixed-debit/_create-quote-debit-amount.mdx'
+import GrantRequestOutgoingPayment from '/src/content/docs/partials/code/guides/onetime-remittance-fixed-debit/_grant-request-outgoing-payment.mdx'
+import CreateOutgoingPayment from '/src/content/docs/partials/code/guides/onetime-remittance-fixed-debit/_create-outgoing-payment.mdx'
+import RequestAGrantContinuation from '/src/content/docs/partials/code/guides/onetime-remittance-fixed-debit/_request-a-grant-continuation.mdx'
:::tip[Summary]
Learn how to send a one-time remittance payment by debiting the sender's account by a specific amount.
@@ -72,79 +80,7 @@ Let's assume the sender has already provided their own wallet address when they
Call the [Get Wallet Address API](/apis/wallet-address-server/operations/get-wallet-address) for each address.
-
-
-
-```ts
-const senderWalletAddress = await client.walletAddress.get({
- url: 'https://cloudninebank.example.com/sender'
-})
-const recipientWalletAddress = await client.walletAddress.get({
- url: 'https://happylifebank.example.com/recipient'
-})
-```
-
-
-
-
-```rust wrap
-let sender_wallet_address = client.wallet_address().get("https://cloudninebank.example.com/sender").await?;
-let recipient_wallet_address = client.wallet_address().get("https://happylifebank.example.com/recipient").await?;
-```
-
-
-
-
-
-```php wrap
-$senderWalletAddress = $client->walletAddress()->get([
- 'url' => 'https://cloudninebank.example.com/sender'
-]);
-$recipientWalletAddress = $client->walletAddress()->get([
- 'url' => 'https://happylifebank.example.com/recipient'
-]);
-```
-
-
-
-
-
-```go wrap
-senderWalletAddress, err := client.WalletAddress.Get(context.TODO(), op.WalletAddressGetParams{
- URL: "https://cloudninebank.example.com/sender",
-})
-if err != nil {
- log.Fatalf("Error fetching sender wallet address: %v\n", err)
-}
-
-recipientWalletAddress, err := client.WalletAddress.Get(context.TODO(), op.WalletAddressGetParams{
- URL: "https://happylifebank.example.com/recipient",
-})
-if err != nil {
- log.Fatalf("Error fetching recipient wallet address: %v\n", err)
-}
-```
-
-
-
-
- ```java wrap
- var senderWalletAddress = client.walletAddress().get("https://cloudninebank.example.com/sender");
- var recipientWalletAddress = client.walletAddress().get("https://happylifebank.example.com/recipient");
- ```
-
-
-
-
-
-```csharp wrap
-var senderWalletAddress = await client.GetWalletAddressAsync("https://cloudninebank.example.com/sender");
-var recipientWalletAddress = await client.GetWalletAddressAsync("https://happylifebank.example.com/recipient");
-```
-
-
-
-
+
Example responses
@@ -181,126 +117,7 @@ Use the recipient's `authServer` details, received in the previous step, to call
This call obtains an access token that allows your app to request that an incoming payment resource be created on the recipient's wallet account.
-
-
-
-```ts wrap
-const recipientIncomingPaymentGrant = await client.grant.request(
- {
- url: recipientWalletAddress.authServer
- },
- {
- access_token: {
- access: [
- {
- type: 'incoming-payment',
- actions: ['create']
- }
- ]
- }
- }
-)
-```
-
-
-
-
-```rust wrap
-use open_payments::types::{AccessTokenRequest, AccessItem, IncomingPaymentAction, GrantRequest};
-let incoming_access = AccessTokenRequest {
- access: vec![AccessItem::IncomingPayment { actions: vec![IncomingPaymentAction::Create, IncomingPaymentAction::Complete], identifier: None }],
-};
-let incoming_grant_request = GrantRequest::new(incoming_access, None);
-let recipient_incoming_payment_grant = client
- .grant()
- .request(&recipient_wallet_address.auth_server, &incoming_grant_request)
- .await?;
-```
-
-
-
-
-
-```php wrap
-$recipientIncomingPaymentGrant = $client->grant()->request([
- 'url' => $recipientWalletAddress->authServer
-], [
- 'access_token' => [
- 'access' => [
- [
- 'type' => 'incoming-payment',
- 'actions' => ['create']
- ]
- ]
- ]
-]);
-```
-
-
-
-
-
-```go wrap
-incomingAccess := as.AccessIncoming{
- Type: as.IncomingPayment,
- Actions: []as.AccessIncomingActions{as.AccessIncomingActionsCreate},
-}
-accessItem := as.AccessItem{}
-if err := accessItem.FromAccessIncoming(incomingAccess); err != nil {
- log.Fatalf("Error creating AccessItem: %v\n", err)
-}
-accessToken := struct {
- Access as.Access `json:"access"`
-}{
- Access: []as.AccessItem{accessItem},
-}
-
-recipientIncomingPaymentGrant, err := client.Grant.Request(context.TODO(), op.GrantRequestParams{
- URL: *recipientWalletAddress.AuthServer,
- RequestBody: as.GrantRequestWithAccessToken{AccessToken: accessToken},
-})
-if err != nil {
- log.Fatalf("Error requesting incoming payment grant: %v\n", err)
-}
-
-```
-
-
-
-
-```java wrap
-var recipientIncomingPaymentGrant = client.auth().grant().incomingPayment(recipientWalletAddress);
-```
-
-
-
-
-
-```csharp wrap
-var recipientIncomingPaymentGrant = await client.RequestGrantAsync(
- new RequestArgs
- {
- Url = recipientWalletAddress.AuthServer,
- },
- new GrantCreateBody
- {
- AccessToken = new AccessToken
- {
- Access =
- [
- new IncomingAccess
- {
- Actions = [Actions.Create]
- }
- ]
- }
- }
-);
-```
-
-
-
-
+
Example response
@@ -336,106 +153,7 @@ Use the access token returned in the previous response to call the
-
-
-```ts wrap
-const recipientIncomingPayment = await client.incomingPayment.create(
- {
- url: recipientWalletAddress.resourceServer,
- accessToken: recipientIncomingPaymentGrant.access_token.value
- },
- {
- walletAddress: recipientWalletAddress.id
- }
-)
-```
-
-
-
-
-```rust wrap
-use open_payments::types::IncomingPaymentRequest;
-let incoming_request = IncomingPaymentRequest {
- wallet_address: recipient_wallet_address.id.clone(),
- incoming_amount: None,
- expires_at: None,
- metadata: None,
-};
-let recipient_incoming_payment = client
- .incoming_payments()
- .create(
- &recipient_wallet_address.resource_server,
- &incoming_request,
- Some(&recipient_incoming_payment_grant.access_token.value),
- )
- .await?;
-```
-
-
-
-
-```php wrap
- $recipientIncomingPayment = $client->incomingPayment()->create(
- [
- 'url' => $recipientWalletAddress->resourceServer,
- 'accessToken' => $recipientIncomingPaymentGrant->access_token->value
- ],
- [
- 'walletAddress' => $recipientWalletAddress->id
- ]
- );
-```
-
-
-
-
-
-```go wrap
-recipientIncomingPayment, err := client.IncomingPayment.Create(context.TODO(), op.IncomingPaymentCreateParams{
- BaseURL: *recipientWalletAddress.ResourceServer,
- AccessToken: recipientIncomingPaymentGrant.AccessToken.Value,
- Payload: rs.CreateIncomingPaymentJSONBody{
- WalletAddressSchema: *recipientWalletAddress.Id,
- },
-})
-if err != nil {
- log.Fatalf("Error creating incoming payment: %v\n", err)
-}
-```
-
-
-
-
-```java wrap
-var recipientIncomingPayment = client.payment().createIncoming(
- recipientWalletAddress,
- recipientIncomingPaymentGrant,
- BigDecimal.valueOf(1700.00)
-);
-```
-
-
-
-
-
-```csharp wrap
-var recipientIncomingPayment = await client.CreateIncomingPaymentAsync(
- new AuthRequestArgs
- {
- Url = recipientWalletAddress.ResourceServer,
- AccessToken = recipientIncomingPaymentGrant.AccessToken.Value
- },
- new IncomingPaymentBody
- {
- WalletAddress = recipientWalletAddress.Id,
- }
-);
-```
-
-
-
-
+
Example response
@@ -471,127 +189,7 @@ Use the sender's `authServer` details, received in Step 1, to call the
-
-
- ```ts wrap
- const senderQuoteGrant = await client.grant.request(
- {
- url: senderWalletAddress.authServer
- },
- {
- access_token: {
- access: [
- {
- type: 'quote',
- actions: ['create']
- }
- ]
- }
- }
- )
- ```
-
-
-
-
-```rust wrap
-use open_payments::types::{AccessTokenRequest, AccessItem, QuoteAction, GrantRequest};
-let quote_access = AccessTokenRequest {
- access: vec![AccessItem::Quote { actions: vec![QuoteAction::Create] }],
-};
-let quote_grant_request = GrantRequest::new(quote_access, None);
-let sender_quote_grant = client
- .grant()
- .request(&sender_wallet_address.auth_server, "e_grant_request)
- .await?;
-```
-
-
-
-
-```php wrap
-$senderQuoteGrant = $client->grant()->request(
- [
- 'url' => $senderWalletAddress->authServer
- ],
- [
- 'access_token' => [
- 'access' => [
- [
- 'type' => 'quote',
- 'actions' => ['create']
- ]
- ]
- ]
- ]
-);
-```
-
-
-
-
-```go wrap
-quoteAccess := as.AccessQuote{
- Type: as.Quote,
- Actions: []as.AccessQuoteActions{as.Create},
-}
-quoteAccessItem := as.AccessItem{}
-if err := quoteAccessItem.FromAccessQuote(quoteAccess); err != nil {
- log.Fatalf("Error creating AccessItem: %v\n", err)
-}
-quoteAccessToken := struct {
- Access as.Access `json:"access"`
-}{
- Access: []as.AccessItem{quoteAccessItem},
-}
-
-senderQuoteGrant, err := client.Grant.Request(context.TODO(), op.GrantRequestParams{
- URL: senderWalletAddress.AuthServer,
- RequestBody: as.GrantRequestWithAccessToken{AccessToken: quoteAccessToken},
-})
-if err != nil {
- log.Fatalf("Error requesting quote grant: %v\n", err)
-}
-
-```
-
-
-
-
-```java wrap
-var senderQuoteGrant = client.auth().grant().quote(senderWalletAddress);
-```
-
-
-
-
-
-```csharp wrap
-var senderQuoteGrant = await client.RequestGrantAsync(
- new RequestArgs
- {
- Url = senderWalletAddress.AuthServer,
- },
- new GrantCreateBody
- {
- AccessToken = new AccessToken
- {
- Access =
- [
- new QuoteAccess
- {
- Actions = [Actions.Create]
- }
- ]
- }
- }
-);
-```
-
-
-
-
+
Example response
@@ -627,146 +225,7 @@ This call requests that a quote resource be created on the sender's wallet accou
The `debitAmount` specifies that the sender will pay exactly $100 USD, and the recipient will receive whatever amount remains after currency conversion.
-
-
- ```ts wrap
- 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
- }
- }
- )
-```
-
-
-
-
-```rust wrap
-use open_payments::types::{QuoteRequest, QuoteMethod, Amount};
-let quote_request = QuoteRequest {
- method: QuoteMethod::Ilp,
- wallet_address: Some(sender_wallet_address.id.clone()),
- receiver: Some(recipient_incoming_payment.id.clone()),
- debit_amount: Some(Amount {
- value: "10000".into(),
- asset_code: "USD".into(),
- asset_scale: 2,
- }),
- receive_amount: None,
-};
-let sender_quote = client
- .quotes()
- .create(
- &sender_wallet_address.resource_server,
- "e_request,
- Some(&sender_quote_grant.access_token.value),
- )
- .await?;
-```
-
-
-
-
-```php wrap
-$senderQuote = $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
- ]
- ]
-);
-```
-
-
-
-
-```go wrap
-senderQuote, err := client.Quote.Create(context.TODO(), op.QuoteCreateParams{
- BaseURL: *senderWalletAddress.ResourceServer,
- AccessToken: senderQuoteGrant.AccessToken.Value,
- Payload: rs.CreateQuoteJSONBody1{
- WalletAddressSchema: *senderWalletAddress.Id,
- Receiver: *recipientIncomingPayment.Id,
- Method: "ilp",
- DebitAmount: rs.Amount{
- Value: "10000",
- AssetCode: "USD",
- AssetScale: 2,
- },
- },
-})
-if err != nil {
- log.Fatalf("Error creating quote: %v\n", err)
-}
-```
-
-
-
-
-```java wrap
-var senderQuote = client.quote().create(
- senderQuoteGrant.getAccess().getToken(),
- senderWalletAddress,
- recipientIncomingPayment,
- Optional.of(
- Amount.build(BigDecimal.valueOf(100.00), "USD", 2)
- ),
- Optional.empty()
-);
-```
-
-
-
-
-
-```csharp wrap
-var senderQuote = await client.CreateQuoteAsync(
- new AuthRequestArgs
- {
- Url = senderWalletAddress.ResourceServer,
- AccessToken = senderQuoteGrant.AccessToken.Value
- },
- new QuoteBodyWithDebitAmount
- {
- Method = PaymentMethod.Ilp,
- WalletAddress = senderWalletAddress.Id,
- Receiver = recipientIncomingPayment.Id,
- DebitAmount = new Amount("10000", "USD", 2)
- }
-);
-```
-
-
-
-
-
-The response returns a `receiveAmount`, a `debitAmount`, and other required information.
-
-- `debitAmount` - The amount the sender must pay (exactly $100.00 USD in our example).
-- `receiveAmount` - The amount the recipient will actually receive ($1,700.00 MXN in our example) after currency conversion.
-
-:::note[Expiring quotes]
-Quotes include an `expiresAt` timestamp. Create the outgoing payment before the quote expires. If creation fails because the quote expired, request a new quote and try again.
-:::
+
Example response
@@ -796,6 +255,15 @@ The following shows an example response from the sender's wallet provider.
+The response returns a `receiveAmount`, a `debitAmount`, and other required information.
+
+- `debitAmount` - The amount the sender must pay (exactly $100.00 USD in our example).
+- `receiveAmount` - The amount the recipient will actually receive ($1,700.00 MXN in our example) after currency conversion.
+
+:::note[Expiring quotes]
+Quotes include an `expiresAt` timestamp. Create the outgoing payment before the quote expires. If creation fails because the quote expired, request a new quote and try again.
+:::
+
### 6. Request an interactive outgoing payment grant
Use the sender's `authServer` information received in Step 1 to call the [Grant Request API](/apis/auth-server/operations/post-request).
@@ -806,239 +274,7 @@ This call obtains an access token that allows your app to request that an outgoi
Outgoing payments require an interactive grant. This type of grant will obtain the sender's consent before an outgoing payment is made against their wallet account. You can find more information in the [Open Payments flow](/concepts/op-flow/#outgoing-payment) and [identity providers](/identity/idp) pages.
:::
-
-
-
-
-```ts wrap
-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
- }
- }
- }
-)
-```
-
-
-
-
-```rust wrap
-use open_payments::types::{
- AccessTokenRequest,
- AccessItem,
- OutgoingPaymentAction,
- AccessLimits,
- Amount,
- InteractRequest,
- InteractStart,
- InteractFinish,
- InteractFinishMethod,
- GrantRequest,
-};
-
-let outgoing_access = AccessTokenRequest {
-access: vec![AccessItem::OutgoingPayment {
-identifier: Some(sender_wallet_address.id.clone()),
-actions: vec![OutgoingPaymentAction::Create],
-limits: Some(AccessLimits {
-debit_amount: Some(Amount {
-value: "10000".into(),
-asset_code: "USD".into(),
-asset_scale: 2,
-}),
-..Default::default()
-}),
-}],
-};
-
-let interact = InteractRequest {
-start: Some(vec![InteractStart::Redirect]),
-finish: Some(InteractFinish {
-method: InteractFinishMethod::Redirect,
-uri: Some("https://myapp.example.com/finish/{...}".into()),
-nonce: Some("NONCE".into()),
-}),
-};
-
-let outgoing_grant_request = GrantRequest::new(outgoing_access, Some(interact));
-
-let pending_sender_outgoing_payment_grant = client
-.grant()
-.request(&sender_wallet_address.auth_server, &outgoing_grant_request)
-.await?;
-
-```
-
-
-
-
-
-```php wrap
-$pendingSenderOutgoingPaymentGrant = $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'
- ]
- ]
- ]
-);
-```
-
-
-
-
-
-```go wrap
-outgoingAccess := as.AccessOutgoing{
- Type: as.OutgoingPayment,
- Actions: []as.AccessOutgoingActions{as.AccessOutgoingActionsCreate},
- Identifier: *senderWalletAddress.Id,
- Limits: &as.LimitsOutgoing{
- DebitAmount: &as.Amount{
- Value: "10000",
- AssetCode: "USD",
- AssetScale: 2,
- },
- },
-}
-outgoingAccessItem := as.AccessItem{}
-if err := outgoingAccessItem.FromAccessOutgoing(outgoingAccess); err != nil {
- log.Fatalf("Error creating AccessItem: %v\n", err)
-}
-outgoingAccessToken := struct {
- Access as.Access `json:"access"`
-}{
- Access: []as.AccessItem{outgoingAccessItem},
-}
-interact := &as.InteractRequest{
- Start: []as.InteractRequestStart{as.InteractRequestStartRedirect},
- Finish: &as.InteractRequestFinish{
- Method: as.Redirect,
- Uri: "https://myapp.example.com/finish/{...}",
- Nonce: NONCE,
- },
-}
-
-pendingSenderOutgoingPaymentGrant, err := client.Grant.Request(context.TODO(), op.GrantRequestParams{
- URL: *senderWalletAddress.AuthServer,
- RequestBody: as.GrantRequestWithAccessToken{
- AccessToken: outgoingAccessToken,
- Interact: interact,
- },
-})
-if err != nil {
- log.Fatalf("Error requesting outgoing payment grant: %v\n", err)
-}
-```
-
-
-
-
-```java wrap
- var debitAmount = Amount.build(BigDecimal.valueOf(100.00), "USD", 2);
- var urlToOpen = "https://myapp.example.com/finish/{...}";
-
-var opContinueInteract = client.auth().grant().continuation(
-senderWalletAddress,
-debitAmount,
-URI.create(urlToOpen),
-"NONCE"
-);
-
-```
-
-
-
-
-
-```csharp wrap
-var pendingSenderOutgoingPaymentGrant = await client.RequestGrantAsync(
- new RequestArgs
- {
- Url = senderWalletAddress.AuthServer,
- },
- new GrantCreateBodyWithInteract
- {
- AccessToken = new AccessToken
- {
- Access =
- [
- new OutgoingAccess
- {
- Identifier = senderWalletAddress.Id,
- Actions = [Actions.Create],
- Limits = new OutgoingAccessLimits
- {
- DebitAmount = new AuthAmount("10000", "USD", 2)
- }
- }
- ]
- },
- Interact = new InteractRequest
- {
- Start = [Start.Redirect],
- Finish = new Finish
- {
- Method = FinishMethod.Redirect,
- Uri = new Uri("https://localhost"), // where to redirect your user after they've completed the interaction
- Nonce = NONCE
- }
- }
- }
-);
-```
-
-
-
-
+
Example response
@@ -1083,102 +319,7 @@ Issue the request to the `continue.uri` provided in the initial outgoing payment
Include the `interact_ref` returned in the redirect URI's query parameters.
-
-
-
- ```ts wrap
- const senderOutgoingPaymentGrant = await client.grant.continue(
- {
- url: pendingSenderOutgoingPaymentGrant.continue.uri,
- accessToken: pendingSenderOutgoingPaymentGrant.continue.access_token.value
- },
- {
- interact_ref: interactRef
- }
- )
- ```
-
-
-
-
-```rust wrap
-let continue_field = match &pending_sender_outgoing_payment_grant.continue_field {
- Some(c) => c,
- None => {
- eprintln!("Missing continue field on pending grant");
- return Ok(());
- }
-};
-let sender_outgoing_payment_grant = client
- .grant()
- .continue_grant(
- &continue_field.uri,
- &interact_ref,
- Some(&continue_field.access_token.value),
- )
- .await?;
-```
-
-
-
-
-```php wrap
-$senderOutgoingPaymentGrant = $client->grant()->continue(
- [
- 'url' => $pendingSenderOutgoingPaymentGrant->continue->uri,
- 'accessToken' => $pendingSenderOutgoingPaymentGrant->continue->access_token->value
- ],
- [
- 'interact_ref' => $interactRef
- ]
-);
-```
-
-
-
-
-```go wrap
-senderOutgoingPaymentGrant, err := client.Grant.Continue(context.TODO(), op.GrantContinueParams{
- URL: pendingSenderOutgoingPaymentGrant.Continue.Uri,
- AccessToken: pendingSenderOutgoingPaymentGrant.Continue.AccessToken.Value,
- InteractRef: INTERACT_REF,
-})
-if err != nil {
- log.Fatalf("Error continuing grant: %v\n", err)
-}
-```
-
-
-
-
-```java wrap
-var senderOutgoingPaymentGrant = client.auth().grant().finalize(
- opContinueInteract,
- interactRef
-);
-```
-
-
-
-
-
-```csharp wrap
-var senderOutgoingPaymentGrant = await client.ContinueGrantAsync(
- new AuthRequestArgs
- {
- Url = pendingSenderOutgoingPaymentGrant.Continue.Uri,
- AccessToken = pendingSenderOutgoingPaymentGrant.Continue.AccessToken.Value
- },
- new GrantContinueBody
- {
- InteractRef = interactRef
- }
-);
-```
-
-
-
-
+
Example response
@@ -1214,118 +355,7 @@ var senderOutgoingPaymentGrant = await client.ContinueGrantAsync(
Use the access token returned in Step 9 to call the [Create Outgoing Payment API](/apis/resource-server/operations/create-outgoing-payment/). Include the `quoteId` in the request. The `quoteId` is the `id` returned in the Create Quote API response (Step 5).
-
-
-
-```ts wrap
-const senderOutgoingPayment = await client.outgoingPayment.create(
- {
- url: senderWalletAddress.resourceServer,
- accessToken: senderOutgoingPaymentGrant.access_token.value
- },
- {
- walletAddress: senderWalletAddress.id,
- quoteId: senderQuote.id
- }
-)
-```
-
-
-
-
-```rust wrap
-use open_payments::types::OutgoingPaymentRequest;
-let outgoing_request = OutgoingPaymentRequest {
- wallet_address: sender_wallet_address.id.clone(),
- receiver: Some(recipient_incoming_payment.id.clone()),
- debit_amount: None,
- receive_amount: None,
- quote_id: Some(sender_quote.id.clone()),
-};
-let sender_outgoing_payment = client
- .outgoing_payments()
- .create(
- &sender_wallet_address.resource_server,
- &outgoing_request,
- Some(&sender_outgoing_payment_grant.access_token.value),
- )
- .await?;
-```
-
-
-
-
-```php wrap
-$senderOutgoingPayment = $client->outgoingPayment()->create(
- [
- 'url' => $senderWalletAddress->resourceServer,
- 'accessToken' => $senderOutgoingPaymentGrant->access_token->value
- ],
- [
- 'walletAddress' => $senderWalletAddress->id,
- 'quoteId' => $senderQuote->id
- ]
-);
-```
-
-
-
-
-```go wrap
-var outgoingPayload rs.CreateOutgoingPaymentRequest
-if err := outgoingPayload.FromCreateOutgoingPaymentWithQuote(rs.CreateOutgoingPaymentWithQuote{
- WalletAddressSchema: *senderWalletAddress.Id,
- QuoteId: *senderQuote.Id,
-}); err != nil {
- log.Fatalf("Error creating payload: %v\n", err)
-}
-
-senderOutgoingPayment, err := client.OutgoingPayment.Create(context.TODO(), op.OutgoingPaymentCreateParams{
- BaseURL: senderWalletAddress.ResourceServer,
- AccessToken: senderOutgoingPaymentGrant.AccessToken.Value,
- Payload: outgoingPayload,
-})
-if err != nil {
- log.Fatalf("Error creating outgoing payment: %v\n", err)
-}
-
-```
-
-
-
-
-```java wrap
-var senderOutgoingPayment = client.payment().createOutgoing(
- senderOutgoingPaymentGrant,
- senderWalletAddress,
- senderQuote
-);
-```
-
-
-
-
-
-```csharp wrap
-var senderOutgoingPayment = await client.CreateOutgoingPaymentAsync(
- new AuthRequestArgs
- {
- Url = senderWalletAddress.ResourceServer,
- AccessToken = senderOutgoingPaymentGrant.AccessToken.Value
- },
- new OutgoingPaymentBodyFromQuote
- {
- WalletAddress = senderWalletAddress.Id,
- QuoteId = senderQuote.Id,
- }
-);
-```
-
-
-
-
-
-If the request fails because of an expired quote, [request a new quote](#5-request-the-creation-of-a-quote-resource) and try again.
+
Example response
@@ -1358,6 +388,7 @@ The following shows an example response when an outgoing payment resource is cre
+If the request fails because of an expired quote, [request a new quote](#5-request-the-creation-of-a-quote-resource) and try again.
:::note[Access token expiry]
If a grant's access token has expired, call the [Rotate Access Token API](/apis/auth-server/operations/post-token/), then use the new token in the appropriate request.
:::
diff --git a/docs/src/content/docs/guides/onetime-remittance-fixed-receive.mdx b/docs/src/content/docs/guides/onetime-remittance-fixed-receive.mdx
index bfb1095a..280b1117 100644
--- a/docs/src/content/docs/guides/onetime-remittance-fixed-receive.mdx
+++ b/docs/src/content/docs/guides/onetime-remittance-fixed-receive.mdx
@@ -6,6 +6,14 @@ import { LinkOut } from '@interledger/docs-design-system'
import { Tabs, TabItem, Badge } from '@astrojs/starlight/components'
import Start from '/src/content/docs/partials/_grant-start-interaction.mdx'
import Finish from '/src/content/docs/partials/_grant-finish-interaction.mdx'
+import GetWalletAddress from '/src/content/docs/partials/code/guides/onetime-remittance-fixed-receive/_get-wallet-address.mdx'
+import GrantRequestIncomingPayment from '/src/content/docs/partials/code/guides/onetime-remittance-fixed-receive/_grant-request-incoming-payment.mdx'
+import CreateIncomingPayment from '/src/content/docs/partials/code/guides/onetime-remittance-fixed-receive/_create-incoming-payment.mdx'
+import GrantRequestQuote from '/src/content/docs/partials/code/guides/onetime-remittance-fixed-receive/_grant-request-quote.mdx'
+import CreateQuoteIlp from '/src/content/docs/partials/code/guides/onetime-remittance-fixed-receive/_create-quote-ilp.mdx'
+import GrantRequestOutgoingPayment from '/src/content/docs/partials/code/guides/onetime-remittance-fixed-receive/_grant-request-outgoing-payment.mdx'
+import CreateOutgoingPayment from '/src/content/docs/partials/code/guides/onetime-remittance-fixed-receive/_create-outgoing-payment.mdx'
+import RequestAGrantContinuation from '/src/content/docs/partials/code/guides/onetime-remittance-fixed-receive/_request-a-grant-continuation.mdx'
:::tip[Summary]
Learn how to send a one-time remittance payment where the recipient will receive a fixed amount.
@@ -74,79 +82,7 @@ Let's assume the sender has already provided their wallet address when they sign
Call the [Get Wallet Address API](/apis/wallet-address-server/operations/get-wallet-address) for each address.
-
-
-
-```ts wrap
-const senderWalletAddress = await client.walletAddress.get({
- url: 'https://cloudninebank.example.com/sender'
-})
-const recipientWalletAddress = await client.walletAddress.get({
- url: 'https://happylifebank.example.com/recipient'
-})
-```
-
-
-
-
-```rust wrap
-let sender_wallet_address = client.wallet_address().get("https://cloudninebank.example.com/sender").await?;
-let recipient_wallet_address = client.wallet_address().get("https://happylifebank.example.com/recipient").await?;
-```
-
-
-
-
-
-```php wrap
-$senderWalletAddress = $client->walletAddress()->get([
- 'url' => 'https://cloudninebank.example.com/sender'
-]);
-$recipientWalletAddress = $client->walletAddress()->get([
- 'url' => 'https://happylifebank.example.com/recipient'
-]);
-```
-
-
-
-
-
-```go wrap
-senderWalletAddress, err := client.WalletAddress.Get(context.TODO(), op.WalletAddressGetParams{
- URL: "https://cloudninebank.example.com/sender",
-})
-if err != nil {
- log.Fatalf("Error fetching sender wallet address: %v\n", err)
-}
-
-recipientWalletAddress, err := client.WalletAddress.Get(context.TODO(), op.WalletAddressGetParams{
- URL: "https://happylifebank.example.com/recipient",
-})
-if err != nil {
- log.Fatalf("Error fetching recipient wallet address: %v\n", err)
-}
-```
-
-
-
-
-```java wrap
-var senderWalletAddress = client.walletAddress().get("https://cloudninebank.example.com/sender");
-var recipientWalletAddress = client.walletAddress().get("https://happylifebank.example.com/recipient");
-```
-
-
-
-
-
-```csharp wrap
-var senderWalletAddress = await client.GetWalletAddressAsync("https://cloudninebank.example.com/sender");
-var recipientWalletAddress = await client.GetWalletAddressAsync("https://happylifebank.example.com/recipient");
-```
-
-
-
-
+
Example responses
@@ -183,130 +119,7 @@ Use the recipient's `authServer` details, received in the previous step, to call
This call obtains an access token that allows your app to request an incoming payment resource be created on the recipient's wallet account.
-
-
-
-```ts wrap
-const recipientIncomingPaymentGrant = await client.grant.request(
- {
- url: recipientWalletAddress.authServer
- },
- {
- access_token: {
- access: [
- {
- type: 'incoming-payment',
- actions: ['create']
- }
- ]
- }
- }
-)
-```
-
-
-
-
-```rust wrap
-use open_payments::types::{AccessTokenRequest, AccessItem, IncomingPaymentAction, GrantRequest};
-
-let incoming_access = AccessTokenRequest {
-access: vec![AccessItem::IncomingPayment { actions: vec![IncomingPaymentAction::Create, IncomingPaymentAction::Complete], identifier: None }],
-};
-let incoming_grant_request = GrantRequest::new(incoming_access, None);
-let recipient_incoming_payment_grant = client
-.grant()
-.request(&recipient_wallet_address.auth_server, &incoming_grant_request)
-.await?;
-
-```
-
-
-
-
-
-```php wrap
-$recipientIncomingPaymentGrant = $client->grant()->request(
- [
- 'url' => $recipientWalletAddress->authServer
- ],
- [
- 'access_token' => [
- 'access' => [
- [
- 'type' => 'incoming-payment',
- 'actions' => ['create']
- ],
- ],
- ],
- ]
-);
-```
-
-
-
-
-
-```go wrap
-incomingAccess := as.AccessIncoming{
- Type: as.IncomingPayment,
- Actions: []as.AccessIncomingActions{as.AccessIncomingActionsCreate},
-}
-accessItem := as.AccessItem{}
-if err := accessItem.FromAccessIncoming(incomingAccess); err != nil {
- log.Fatalf("Error creating AccessItem: %v\n", err)
-}
-accessToken := struct {
- Access as.Access `json:"access"`
-}{
- Access: []as.AccessItem{accessItem},
-}
-
-recipientIncomingPaymentGrant, err := client.Grant.Request(context.TODO(), op.GrantRequestParams{
- URL: *recipientWalletAddress.AuthServer,
- RequestBody: as.GrantRequestWithAccessToken{AccessToken: accessToken},
-})
-if err != nil {
- log.Fatalf("Error requesting incoming payment grant: %v\n", err)
-}
-```
-
-
-
-
-```java wrap
-var recipientIncomingPaymentGrant = client.auth().grant().incomingPayment(recipientWalletAddress);
-```
-
-
-
-
-
-```csharp wrap
-var recipientIncomingPaymentGrant = await client.RequestGrantAsync(
- new RequestArgs
- {
- Url = recipientWalletAddress.AuthServer,
- },
- new GrantCreateBody
- {
- AccessToken = new AccessToken
- {
- Access =
- [
- new IncomingAccess
- {
- Actions = [Actions.Create]
- }
- ]
- }
- }
-);
-```
-
-
-
-
+
Example response
@@ -342,109 +155,7 @@ Use the access token returned in the previous response to call the
-
-
-```ts wrap
-const recipientIncomingPayment = await client.incomingPayment.create(
- {
- url: recipientWalletAddress.resourceServer,
- accessToken: recipientIncomingPaymentGrant.access_token.value
- },
- {
- walletAddress: recipientWalletAddress.id
- }
-)
-```
-
-
-
-
-```rust wrap
-use open_payments::types::IncomingPaymentRequest;
-
-let incoming_request = IncomingPaymentRequest {
-wallet_address: recipient_wallet_address.id.clone(),
-incoming_amount: None,
-expires_at: None,
-metadata: None,
-};
-let recipient_incoming_payment = client
-.incoming_payments()
-.create(
-&recipient_wallet_address.resource_server,
-&incoming_request,
-Some(&recipient_incoming_payment_grant.access_token.value),
-)
-.await?;
-
-```
-
-
-
-
-
-```php wrap
-$recipientIncomingPayment = $client->incomingPayment()->create(
- [
- 'url' => $recipientWalletAddress->resourceServer,
- 'accessToken' => $recipientIncomingPaymentGrant->access_token->value
- ],
- [
- 'walletAddress' => $recipientWalletAddress->id,
- ]
-);
-```
-
-
-
-
-
-```go wrap
-recipientIncomingPayment, err := client.IncomingPayment.Create(context.TODO(), op.IncomingPaymentCreateParams{
- BaseURL: *recipientWalletAddress.ResourceServer,
- AccessToken: recipientIncomingPaymentGrant.AccessToken.Value,
- Payload: rs.CreateIncomingPaymentJSONBody{
- WalletAddressSchema: *recipientWalletAddress.Id,
- },
-})
-if err != nil {
- log.Fatalf("Error creating incoming payment: %v\n", err)
-}
-```
-
-
-
-
-```java wrap
-var recipientIncomingPayment = client.payment().createIncoming(
- recipientWalletAddress,
- recipientIncomingPaymentGrant,
- BigDecimal.valueOf(5000.00)
-);
-```
-
-
-
-
-
-```csharp wrap
-var recipientIncomingPayment = await client.CreateIncomingPaymentAsync(
- new AuthRequestArgs
- {
- Url = recipientWalletAddress.ResourceServer,
- AccessToken = recipientIncomingPaymentGrant.AccessToken.Value
- },
- new IncomingPaymentBody
- {
- WalletAddress = recipientWalletAddress.Id,
- }
-);
-```
-
-
-
-
+
Example response
@@ -480,135 +191,7 @@ Use the sender's `authServer` details, received in Step 1, to call the
-
-
-```ts wrap
-const senderQuoteGrant = await client.grant.request(
- {
- url: senderWalletAddress.authServer
- },
- {
- access_token: {
- access: [
- {
- type: 'quote',
- actions: ['create']
- }
- ]
- }
- }
-)
-```
-
-
-
-
-```rust wrap
-use open_payments::types::{
- AccessTokenRequest,
- AccessItem,
- QuoteAction,
- GrantRequest,
-};
-
-let quote_access = AccessTokenRequest {
-access: vec![AccessItem::Quote { actions: vec![QuoteAction::Create] }],
-};
-let quote_grant_request = GrantRequest::new(quote_access, None);
-let sender_quote_grant = client
-.grant()
-.request(&sender_wallet_address.auth_server, "e_grant_request)
-.await?;
-
-```
-
-
-
-
-
-```php wrap
-$senderQuoteGrant = $client->grant()->request(
- [
- 'url' => $senderWalletAddress->authServer
- ],
- [
- 'access_token' => [
- 'access' => [
- [
- 'type' => 'quote',
- 'actions' => ['create']
- ]
- ]
- ]
- ]
-);
-```
-
-
-
-
-
-```go wrap
-quoteAccess := as.AccessQuote{
- Type: as.Quote,
- Actions: []as.AccessQuoteActions{as.Create},
-}
-quoteAccessItem := as.AccessItem{}
-if err := quoteAccessItem.FromAccessQuote(quoteAccess); err != nil {
- log.Fatalf("Error creating AccessItem: %v\n", err)
-}
-quoteAccessToken := struct {
- Access as.Access `json:"access"`
-}{
- Access: []as.AccessItem{quoteAccessItem},
-}
-
-senderQuoteGrant, err := client.Grant.Request(context.TODO(), op.GrantRequestParams{
- URL: senderWalletAddress.AuthServer,
- RequestBody: as.GrantRequestWithAccessToken{AccessToken: quoteAccessToken},
-})
-if err != nil {
- log.Fatalf("Error requesting quote grant: %v\n", err)
-}
-```
-
-
-
-
-```java wrap
-var senderQuoteGrant = client.auth().grant().quote(senderWalletAddress);
-```
-
-
-
-
-
-```csharp wrap
-var senderQuoteGrant = await client.RequestGrantAsync(
- new RequestArgs
- {
- Url = senderWalletAddress.AuthServer,
- },
- new GrantCreateBody
- {
- AccessToken = new AccessToken
- {
- Access =
- [
- new QuoteAccess
- {
- Actions = [Actions.Create]
- }
- ]
- }
- }
-);
-```
-
-
-
-
+
Example response
@@ -646,149 +229,7 @@ This call requests that a quote resource be created on the sender's wallet accou
The `receiveAmount` specifies that the recipient will receive exactly $5,000 MXN.
-
-
-
-```ts wrap
-const senderQuote = await client.quote.create(
- {
- url: senderWalletAddress.resourceServer,
- accessToken: senderQuoteGrant.access_token.value
- },
- {
- method: 'ilp',
- walletAddress: senderWalletAddress.id,
- receiver: recipientIncomingPayment.id,
- receiveAmount: {
- value: '500000',
- assetCode: 'MXN',
- assetScale: 2
- }
- }
-)
-```
-
-
-
-
-```rust wrap
-use open_payments::types::{QuoteRequest, QuoteMethod, Amount};
-
-let quote_request = QuoteRequest {
-method: QuoteMethod::Ilp,
-wallet_address: Some(sender_wallet_address.id.clone()),
-receiver: Some(recipient_incoming_payment.id.clone()),
-debit_amount: None,
-receive_amount: Some(Amount { value: "500000".into(), asset_code: "MXN".into(), asset_scale: 2 }),
-};
-let sender_quote = client
-.quotes()
-.create(
-&sender_wallet_address.resource_server,
-"e_request,
-Some(&sender_quote_grant.access_token.value),
-)
-.await?;
-
-```
-
-
-
-
-
-```php wrap
-$senderQuote = $client->quote()->create(
- [
- 'url' => $senderWalletAddress->resourceServer,
- 'accessToken' => $senderQuoteGrant->access_token->value
- ],
- [
- 'method' => 'ilp',
- 'walletAddress' => $senderWalletAddress->id,
- 'receiver' => $recipientIncomingPayment->id,
- 'receiveAmount' => [
- 'value' => '500000',
- 'assetCode' => 'MXN',
- 'assetScale' => 2
- ]
- ]
-);
-```
-
-
-
-
-
-```go wrap
-senderQuote, err := client.Quote.Create(context.TODO(), op.QuoteCreateParams{
- BaseURL: *senderWalletAddress.ResourceServer,
- AccessToken: senderQuoteGrant.AccessToken.Value,
- Payload: rs.CreateQuoteJSONBody2{
- WalletAddressSchema: *senderWalletAddress.Id,
- Receiver: *recipientIncomingPayment.Id,
- Method: "ilp",
- ReceiveAmount: rs.Amount{
- Value: "500000",
- AssetCode: "MXN",
- AssetScale: 2,
- },
- },
-})
-if err != nil {
- log.Fatalf("Error creating quote: %v\n", err)
-}
-```
-
-
-
-
-```java wrap
-var senderQuote = client.quote().create(
- senderQuoteGrant.getAccess().getToken(),
- senderWalletAddress,
- recipientIncomingPayment,
- Optional.empty(),
- Optional.of(
- Amount.build(BigDecimal.valueOf(5000.00), "MXN", 2)
- )
-);
-```
-
-
-
-
-
-```csharp wrap
-var senderQuote = await client.CreateQuoteAsync(
- new AuthRequestArgs
- {
- Url = senderWalletAddress.ResourceServer,
- AccessToken = senderQuoteGrant.AccessToken.Value
- },
- new QuoteBodyWithReceiveAmount
- {
- Method = PaymentMethod.Ilp,
- WalletAddress = senderWalletAddress.Id,
- Receiver = recipientIncomingPayment.Id,
- ReceiveAmount = new Amount("500000", "MXN", 2)
- }
-);
-```
-
-
-
-
-
-The response returns a `receiveAmount`, a `debitAmount`, and other required information.
-
-- `debitAmount` - The amount the sender must pay (in USD in our example) after currency conversion.
-- `receiveAmount` - The amount the recipient will actually receive (exactly $5,000 MXN in our example).
-
-You'll use this same `receiveAmount` in the next step when requesting the outgoing payment grant, so the sender authorizes this exact amount.
-
-:::note[Expiring quotes]
-Quotes include an `expiresAt` timestamp. Create the outgoing payment before the quote expires. If creation fails because the quote expired, request a new quote and try again.
-:::
+
Example response
@@ -818,6 +259,17 @@ The following shows an example response from the sender’s wallet provider.
+The response returns a `receiveAmount`, a `debitAmount`, and other required information.
+
+- `debitAmount` - The amount the sender must pay (in USD in our example) after currency conversion.
+- `receiveAmount` - The amount the recipient will actually receive (exactly $5,000 MXN in our example).
+
+You'll use this same `receiveAmount` in the next step when requesting the outgoing payment grant, so the sender authorizes this exact amount.
+
+:::note[Expiring quotes]
+Quotes include an `expiresAt` timestamp. Create the outgoing payment before the quote expires. If creation fails because the quote expired, request a new quote and try again.
+:::
+
### 6. Request an interactive outgoing payment grant
Use the sender's `authServer` information received in Step 1 to call the [Grant Request API](/apis/auth-server/operations/post-request).
@@ -830,230 +282,7 @@ To ensure the sender is authorizing the correct amount, include the same `receiv
Outgoing payments require an interactive grant. This type of grant will obtain the sender's consent before an outgoing payment is made against their wallet account. You can find more information in the [Open Payments flow](/concepts/op-flow/#outgoing-payment) and [identity providers](/identity/idp) pages.
:::
-
-
-
-```ts wrap
-const pendingSenderOutgoingPaymentGrant = await client.grant.request(
- {
- url: senderWalletAddress.authServer
- },
- {
- access_token: {
- access: [
- {
- identifier: senderWalletAddress.id,
- type: 'outgoing-payment',
- actions: ['create'],
- limits: {
- receiveAmount: {
- assetCode: 'MXN',
- assetScale: 2,
- value: '500000'
- }
- }
- }
- ]
- },
- 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
- }
- }
- }
-)
-```
-
-
-
-
-```rust wrap
-use open_payments::types::{
- AccessTokenRequest,
- AccessItem,
- OutgoingPaymentAction,
- InteractRequest,
- InteractStart,
- InteractFinish,
- InteractFinishMethod,
- AccessLimits,
- Amount,
- GrantRequest,
-};
-
-let outgoing_access = AccessTokenRequest {
-access: vec![AccessItem::OutgoingPayment {
-identifier: Some(sender_wallet_address.id.clone()),
-actions: vec![OutgoingPaymentAction::Create],
-limits: Some(AccessLimits {
-receive_amount: Some(Amount { value: "500000".into(), asset_code: "MXN".into(), asset_scale: 2 }),
-..Default::default()
-}),
-}],
-};
-let interact = InteractRequest {
-start: Some(vec![InteractStart::Redirect]),
-finish: Some(InteractFinish {
-method: InteractFinishMethod::Redirect,
-uri: Some("https://myapp.example.com/finish/{...}".into()),
-nonce: Some("NONCE".into()),
-}),
-};
-let outgoing_grant_request = GrantRequest::new(outgoing_access, Some(interact));
-let pending_sender_outgoing_payment_grant = client
-.grant()
-.request(&sender_wallet_address.auth_server, &outgoing_grant_request)
-.await?;
-
-```
-
-
-
-
-
-```php wrap
-$pendingSenderOutgoingPaymentGrant = $client->grant()->request(
- [
- 'url' => $senderWalletAddress->authServer
- ],
- [
- 'access_token' => [
- 'access' => [
- [
- 'identifier' => $senderWalletAddress->id,
- 'type' => 'outgoing-payment',
- 'actions' => ['create'],
- 'limits' => [
- 'receiveAmount' => [
- 'assetCode' => 'MXN',
- 'assetScale' => 2,
- 'value' => '500000'
- ]
- ]
- ]
- ]
- ],
- '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'
- ]
- ]
- ]
-);
-```
-
-
-
-
-
-```go wrap
-outgoingAccess := as.AccessOutgoing{
- Type: as.OutgoingPayment,
- Actions: []as.AccessOutgoingActions{as.AccessOutgoingActionsCreate},
- Identifier: *senderWalletAddress.Id,
- Limits: &as.LimitsOutgoing{
- ReceiveAmount: &as.Amount{
- Value: "500000",
- AssetCode: "MXN",
- AssetScale: 2,
- },
- },
-}
-outgoingAccessItem := as.AccessItem{}
-if err := outgoingAccessItem.FromAccessOutgoing(outgoingAccess); err != nil {
- log.Fatalf("Error creating AccessItem: %v\n", err)
-}
-outgoingAccessToken := struct {
- Access as.Access `json:"access"`
-}{
- Access: []as.AccessItem{outgoingAccessItem},
-}
-interact := &as.InteractRequest{
- Start: []as.InteractRequestStart{as.InteractRequestStartRedirect},
- Finish: &as.InteractRequestFinish{
- Method: as.Redirect,
- Uri: "https://myapp.example.com/finish/{...}",
- Nonce: NONCE,
- },
-}
-
-pendingSenderOutgoingPaymentGrant, err := client.Grant.Request(context.TODO(), op.GrantRequestParams{
- URL: *senderWalletAddress.AuthServer,
- RequestBody: as.GrantRequestWithAccessToken{
- AccessToken: outgoingAccessToken,
- Interact: interact,
- },
-})
-if err != nil {
- log.Fatalf("Error requesting outgoing payment grant: %v\n", err)
-}
-```
-
-
-
-
-```java wrap
- var urlToOpen = "https://myapp.example.com/finish/{...}";
-
-var opContinueInteract = client.auth().grant().continuation(
-senderWalletAddress,
-senderQuote.getDebitAmount(),
-URI.create(urlToOpen),
-"NONCE"
-);
-
-```
-
-
-
-
-
-```csharp wrap
-var pendingSenderOutgoingPaymentGrant = await client.RequestGrantAsync(
- new RequestArgs
- {
- Url = senderWalletAddress.AuthServer,
- },
- new GrantCreateBodyWithInteract
- {
- AccessToken = new AccessToken
- {
- Access =
- [
- new OutgoingAccess
- {
- Identifier = senderWalletAddress.Id,
- Actions = [Actions.Create],
- Limits = new OutgoingAccessLimits
- {
- ReceiveAmount = new AuthAmount("500000", "MXN", 2)
- }
- }
- ]
- },
- Interact = new InteractRequest
- {
- Start = [Start.Redirect],
- Finish = new Finish
- {
- Method = FinishMethod.Redirect,
- Uri = new Uri("https://localhost"), // where to redirect your user after they've completed the interaction
- Nonce = NONCE
- }
- }
- }
-);
-```
-
-
-
-
+
Example response
@@ -1100,104 +329,7 @@ Issue the request to the `continue.uri` provided in the initial outgoing payment
Include the `interact_ref` returned in the redirect URI's query parameters.
-
-
-
-```ts wrap
-const senderOutgoingPaymentGrant = await client.grant.continue(
- {
- url: pendingSenderOutgoingPaymentGrant.continue.uri,
- accessToken: pendingSenderOutgoingPaymentGrant.continue.access_token.value
- },
- {
- interact_ref: interactRef
- }
-)
-```
-
-
-
-
-```rust wrap
-let continue_field = match &pending_sender_outgoing_payment_grant.continue_field {
- Some(c) => c,
- None => {
- eprintln!("Missing continue field on pending grant");
- return Ok(());
- }
-};
-let sender_outgoing_payment_grant = client
- .grant()
- .continue_grant(
- &continue_field.uri,
- &interact_ref,
- Some(&continue_field.access_token.value),
- )
- .await?;
-```
-
-
-
-
-
-```php wrap
-$senderOutgoingPaymentGrant = $client->grant()->continue(
- [
- 'url' => $pendingSenderOutgoingPaymentGrant->continue->uri,
- 'accessToken' => $pendingSenderOutgoingPaymentGrant->continue->access_token->value
- ],
- [
- 'interact_ref' => $interactRef
- ]
-);
-```
-
-
-
-
-
-```go wrap
-senderOutgoingPaymentGrant, err := client.Grant.Continue(context.TODO(), op.GrantContinueParams{
- URL: pendingSenderOutgoingPaymentGrant.Continue.Uri,
- AccessToken: pendingSenderOutgoingPaymentGrant.Continue.AccessToken.Value,
- InteractRef: INTERACT_REF,
-})
-if err != nil {
- log.Fatalf("Error continuing grant: %v\n", err)
-}
-```
-
-
-
-
-```java wrap
-var senderOutgoingPaymentGrant = client.auth().grant().finalize(
- opContinueInteract,
- interactRef
-);
-```
-
-
-
-
-
-```csharp wrap
-var senderOutgoingPaymentGrant = await client.ContinueGrantAsync(
- new AuthRequestArgs
- {
- Url = pendingSenderOutgoingPaymentGrant.Continue.Uri,
- AccessToken = pendingSenderOutgoingPaymentGrant.Continue.AccessToken.Value
- },
- new GrantContinueBody
- {
- InteractRef = interactRef
- }
-);
-```
-
-
-
-
+
Example response
@@ -1235,119 +367,7 @@ The following shows an example response from the sender's wallet provider.
Use the access token returned in Step 9 to call the [Create Outgoing Payment API](/apis/resource-server/operations/create-outgoing-payment/). Include the `quoteId` in the request. The `quoteId` is the `id` returned in the Create Quote API response (Step 5).
-
-
-
-```ts wrap
-const senderOutgoingPayment = await client.outgoingPayment.create(
- {
- url: senderWalletAddress.resourceServer,
- accessToken: senderOutgoingPaymentGrant.access_token.value
- },
- {
- walletAddress: senderWalletAddress.id,
- quoteId: senderQuote.id
- }
-)
-```
-
-
-
-
-```rust wrap
-use open_payments::types::OutgoingPaymentRequest;
-let outgoing_request = OutgoingPaymentRequest {
- wallet_address: sender_wallet_address.id.clone(),
- receiver: Some(recipient_incoming_payment.id.clone()),
- debit_amount: None,
- receive_amount: None,
- quote_id: Some(sender_quote.id.clone()),
-};
-let sender_outgoing_payment = client
- .outgoing_payments()
- .create(
- &sender_wallet_address.resource_server,
- &outgoing_request,
- Some(&sender_outgoing_payment_grant.access_token.value),
- )
- .await?;
-```
-
-
-
-
-
-```php wrap
- $senderOutgoingPayment = $client->outgoingPayment()->create(
- [
- 'url' => $senderWalletAddress->resourceServer,
- 'accessToken' => $senderOutgoingPaymentGrant->access_token->value
- ],
- [
- 'walletAddress' => $senderWalletAddress->id,
- 'quoteId' => $senderQuote->id
- ]
-);
-```
-
-
-
-
-
-```go wrap
-var outgoingPayload rs.CreateOutgoingPaymentRequest
-if err := outgoingPayload.FromCreateOutgoingPaymentWithQuote(rs.CreateOutgoingPaymentWithQuote{
- WalletAddressSchema: *senderWalletAddress.Id,
- QuoteId: *senderQuote.Id,
-}); err != nil {
- log.Fatalf("Error creating payload: %v\n", err)
-}
-
-senderOutgoingPayment, err := client.OutgoingPayment.Create(context.TODO(), op.OutgoingPaymentCreateParams{
- BaseURL: *senderWalletAddress.ResourceServer,
- AccessToken: senderOutgoingPaymentGrant.AccessToken.Value,
- Payload: outgoingPayload,
-})
-if err != nil {
- log.Fatalf("Error creating outgoing payment: %v\n", err)
-}
-```
-
-
-
-
-```java wrap
-var senderOutgoingPayment = client.payment().createOutgoing(
- senderOutgoingPaymentGrant,
- senderWalletAddress,
- senderQuote
-);
-```
-
-
-
-
-
-```csharp wrap
-var senderOutgoingPayment = await client.CreateOutgoingPaymentAsync(
- new AuthRequestArgs
- {
- Url = senderWalletAddress.ResourceServer,
- AccessToken = senderOutgoingPaymentGrant.AccessToken.Value
- },
- new OutgoingPaymentBodyFromQuote
- {
- WalletAddress = senderWalletAddress.Id,
- QuoteId = senderQuote.Id,
- }
-);
-```
-
-
-
-
-
-If the request fails because of an expired quote, [request a new quote](#5-request-the-creation-of-a-quote-resource) and try again.
+
Example response
@@ -1380,6 +400,7 @@ The following shows an example response from the sender's wallet provider.
+If the request fails because of an expired quote, [request a new quote](#5-request-the-creation-of-a-quote-resource) and try again.
:::note[Access token expiry]
If a grant's access token has expired, call the [Rotate Access Token API](/apis/auth-server/operations/post-token/), then use the new token in the appropriate request.
:::
diff --git a/docs/src/content/docs/guides/outgoing-grant-future-payments.mdx b/docs/src/content/docs/guides/outgoing-grant-future-payments.mdx
index 14dbf951..6f698746 100644
--- a/docs/src/content/docs/guides/outgoing-grant-future-payments.mdx
+++ b/docs/src/content/docs/guides/outgoing-grant-future-payments.mdx
@@ -7,6 +7,9 @@ import { Tabs, TabItem, Badge } from '@astrojs/starlight/components'
import InteractionReq from '/src/content/docs/partials/_interaction-required.mdx'
import Start from '/src/content/docs/partials/_grant-start-interaction.mdx'
import Finish from '/src/content/docs/partials/_grant-finish-interaction.mdx'
+import GetWalletAddress from '/src/content/docs/partials/code/guides/outgoing-grant-future-payments/_get-wallet-address.mdx'
+import GrantRequestOutgoingPayment from '/src/content/docs/partials/code/guides/outgoing-grant-future-payments/_grant-request-outgoing-payment.mdx'
+import RequestAGrantContinuation from '/src/content/docs/partials/code/guides/outgoing-grant-future-payments/_request-a-grant-continuation.mdx'
:::tip[Summary]
Learn how to get an outgoing payment grant for future payments without specifying any recipients.
@@ -45,64 +48,7 @@ For this guide, you'll assume the role of an app developer. The guide explains h
Let's assume your user saved their wallet address in their account profile when setting up your app. Call the [Get Wallet Address API](/apis/wallet-address-server/operations/get-wallet-address).
-
-
-
-```ts
-const userWalletAddress = await client.walletAddress.get({
- url: 'https://cloudninebank.example.com/user'
-})
-```
-
-
-
-
-```rust wrap
-let user_wallet_address = client.wallet_address().get("https://cloudninebank.example.com/user").await?;
-```
-
-
-
-
-
-```php wrap
-$userWalletAddress = $client->walletAddress()->get([
- 'url' => 'https://cloudninebank.example.com/user'
-]);
-```
-
-
-
-
-
-```go wrap
-userWalletAddress, err := client.WalletAddress.Get(context.TODO(), op.WalletAddressGetParams{
- URL: "https://cloudninebank.example.com/user",
-})
-if err != nil {
- log.Fatalf("Error fetching user wallet address: %v\n", err)
-}
-```
-
-
-
-
-
-```java wrap
-var userWalletAddress = client.walletAddress().get("https://cloudninebank.example.com/user");
-```
-
-
-
-
-
-```csharp wrap
-var userWalletAddress = await client.GetWalletAddressAsync("https://cloudninebank.example.com/user");
-```
-
-
-
-
+
Example response
@@ -127,238 +73,6 @@ This call obtains a token that allows your app to request outgoing payment resou
-Remember, your user wants to send payments of up to $100 CAD a month for three months. The amount resets each month and any unspent portions don't roll over.
-
-
-
-
-```ts
-const grant = await client.grant.request(
- {
- url: userWalletAddress.authServer,
- },
- {
- access_token: {
- access: [
- {
- identifier: userWalletAddress.id,
- type: 'outgoing-payment',
- actions: ['read', 'create'],
- limits: {
- interval: 'R3/2025-05-20T13:00:00Z/P1M'
- debitAmount: {
- assetCode: 'CAD',
- assetScale: 2,
- value: '10000',
- },
- },
- },
- ],
- },
- client: userWalletAddress.id,
- interact: {
- start: ['redirect'],
- finish: {
- method: 'redirect',
- uri: 'https://paymentplatform.example/finish/{...}', // where to redirect the user to after they've completed the interaction
- nonce: NONCE,
- },
- },
- },
-);
-```
-
-
-
-
-```rust wrap
-use open_payments::types::{AccessTokenRequest, AccessItem, OutgoingPaymentAction, AccessLimits, Amount, InteractRequest, InteractStart, InteractFinish, InteractFinishMethod, GrantRequest};
-let outgoing_access = AccessTokenRequest {
- access: vec![AccessItem::OutgoingPayment {
- identifier: Some(user_wallet_address.id.clone()),
- actions: vec![OutgoingPaymentAction::Create, OutgoingPaymentAction::Read],
- limits: Some(AccessLimits {
- interval: Some("R3/2025-05-20T13:00:00Z/P1M".into()),
- debit_amount: Some(Amount { value: "10000".into(), asset_code: "CAD".into(), asset_scale: 2 }),
- ..Default::default()
- }),
- }],
-};
-let interact = InteractRequest { start: Some(vec![InteractStart::Redirect]), finish: Some(InteractFinish { method: InteractFinishMethod::Redirect, uri: Some("https://paymentplatform.example/finish/{...}".into()), nonce: Some("NONCE".into()) }) };
-let outgoing_grant_request = GrantRequest::new(outgoing_access, Some(interact));
-let pending_user_outgoing_payment_grant = client
- .grant()
- .request(&user_wallet_address.auth_server, &outgoing_grant_request)
- .await?;
-```
-
-
-
-
-```php wrap
-$grant = $client->grant()->request(
- [
- 'url' => $userWalletAddress->authServer,
- ],
- [
- 'access_token' => [
- 'access' => [
- [
- 'identifier' => $userWalletAddress->id,
- 'type' => 'outgoing-payment',
- 'actions' => ['read', 'create'],
- 'limits' => [
- 'interval' => 'R3/2025-05-20T13:00:00Z/P1M',
- 'debitAmount' => [
- 'assetCode' => 'CAD',
- 'assetScale' => 2,
- 'value' => '10000',
- ],
- ],
- ],
- ],
- ],
- 'client' => $userWalletAddress->id,
- 'interact' => [
- 'start' => ['redirect'],
- 'finish' => [
- 'method' => 'redirect',
- 'uri' => 'https://paymentplatform.example/finish/{...}', // where to redirect the user to after they've completed the interaction
- 'nonce' => NONCE,
- ],
- ],
- ],
-);
-```
-
-
-
-
-```go wrap
-interval := "R3/2025-05-20T13:00:00Z/P1M"
-limits := as.LimitsOutgoing{}
-if err := limits.FromLimitsOutgoing1(as.LimitsOutgoing1{
- Interval: &interval,
- DebitAmount: as.Amount{
- Value: "10000",
- AssetCode: "CAD",
- AssetScale: 2,
- },
-}); err != nil {
- log.Fatalf("Error creating limits: %v\n", err)
-}
-
-outgoingAccess := as.AccessOutgoing{
- Type: as.OutgoingPayment,
- Actions: []as.AccessOutgoingActions{as.AccessOutgoingActionsCreate, as.AccessOutgoingActionsRead},
- Identifier: *userWalletAddress.Id,
- Limits: &limits,
-}
-outgoingAccessItem := as.AccessItem{}
-if err := outgoingAccessItem.FromAccessOutgoing(outgoingAccess); err != nil {
- log.Fatalf("Error creating AccessItem: %v\n", err)
-}
-outgoingAccessToken := struct {
- Access as.Access `json:"access"`
-}{
- Access: []as.AccessItem{outgoingAccessItem},
-}
-interact := &as.InteractRequest{
- Start: []as.InteractRequestStart{as.InteractRequestStartRedirect},
- Finish: &as.InteractRequestFinish{
- Method: as.Redirect,
- Uri: "https://paymentplatform.example/finish/{...}",
- Nonce: NONCE,
- },
-}
-
-pendingUserOutgoingPaymentGrant, err := client.Grant.Request(context.TODO(), op.GrantRequestParams{
- URL: *userWalletAddress.AuthServer,
- RequestBody: as.GrantRequestWithAccessToken{
- AccessToken: outgoingAccessToken,
- Interact: interact,
- },
-})
-if err != nil {
- log.Fatalf("Error requesting outgoing payment grant: %v\n", err)
-}
-```
-
-
-
-
-
-```java wrap
-var interval = "R3/2025-05-20T13:00:00Z/P1M";
-
-var limits = LimitsOutgoing.build(
- interval,
- Amount.build(BigDecimal.valueOf(100.00), "CAD", 2)
-);
-
-var accessRequest = AccessTokenRequest.build(
- userWalletAddress.getId(),
- limits
-);
-
-var urlToOpen = "https://paymentplatform.example/finish/{...}";
-
-var grantRequest = client.auth().grant().request(
- userWalletAddress,
- accessRequest,
- URI.create(urlToOpen),
- "NONCE"
-);
-```
-
-
-
-
-
-```csharp wrap
-var grant = await client.RequestGrantAsync(
- new RequestArgs
- {
- Url = userWalletAddress.AuthServer,
- },
- new GrantCreateBodyWithInteract
- {
- AccessToken = new AccessToken
- {
- Access =
- [
- new OutgoingAccess
- {
- Identifier = userWalletAddress.Id,
- Actions = [Actions.Create, Actions.Read],
- Limits = new OutgoingAccessLimits
- {
- DebitAmount = new AuthAmount("10000", "CAD", 2),
- Interval = "R3/2025-05-20T13:00:00Z/P1M"
- }
- }
- ]
- },
- Client = userWalletAddress.Id,
- Interact = new InteractRequest
- {
- Start = [Start.Redirect],
- Finish = new Finish
- {
- Method = FinishMethod.Redirect,
- Uri = new Uri(
- "https://localhost"), // where to redirect your user after they've completed the interaction
- Nonce = NONCE
- }
- }
- }
-);
-```
-
-
-
-
-
Example response
@@ -380,6 +94,9 @@ var grant = await client.RequestGrantAsync(
+Remember, your user wants to send payments of up to $100 CAD a month for three months. The amount resets each month and any unspent portions don't roll over.
+
+
#### About the interval
The interval used in this guide is `R3/2025-05-20T13:00:00Z/P1M`. Your user wants to send payments up to $100 CAD a month for three months. The interval breaks down like this:
@@ -417,107 +134,7 @@ Issue the request to the `continue.uri` provided in the initial outgoing payment
Include the `interact_ref` returned in the redirect URI's query parameters.
-
-
-
-```ts wrap
-const userOutgoingPaymentGrant = await client.grant.continue(
- {
- accessToken: pendingUserOutgoingPaymentGrant.continue.acces_token.value,
- url: pendingUserOutgoingPaymentGrant.continue.uri
- },
- {
- interact_ref: interactRef
- }
-)
-```
-
-
-
-
-```rust wrap
-let continue_field = match &pending_user_outgoing_payment_grant.continue_field {
- Some(c) => c,
- None => {
- eprintln!("Missing continue field on pending grant");
- return Ok(());
- }
-};
-let user_outgoing_payment_grant = client
- .grant()
- .continue_grant(
- &continue_field.uri,
- &interact_ref,
- Some(&continue_field.access_token.value),
- )
- .await?;
-```
-
-
-
-
-
-```php wrap
-$userOutgoingPaymentGrant = $client->grant()->continue(
- [
- 'accessToken' => $pendingUserOutgoingPaymentGrant->continue->access_token->value,
- 'url' => $pendingUserOutgoingPaymentGrant->continue->uri,
- ],
- [
- 'interact_ref' => $interactRef,
- ],
-);
-```
-
-
-
-
-
-```go wrap
-userOutgoingPaymentGrant, err := client.Grant.Continue(context.TODO(), op.GrantContinueParams{
- URL: pendingUserOutgoingPaymentGrant.Continue.Uri,
- AccessToken: pendingUserOutgoingPaymentGrant.Continue.AccessToken.Value,
- InteractRef: INTERACT_REF,
-})
-if err != nil {
- log.Fatalf("Error continuing grant: %v\n", err)
-}
-```
-
-
-
-
-
-```java wrap
-var userOutgoingPaymentGrant = client.auth().grant().finalize(
- grantRequest,
- interactRef
-);
-```
-
-
-
-
-
-```csharp wrap
-var userOutgoingPaymentGrant = await client.ContinueGrantAsync(
- new AuthRequestArgs
- {
- Url = grant.Continue.Uri,
- AccessToken = grant.Continue.AccessToken.Value
- },
- new GrantContinueBody()
- {
- InteractRef = interactRef
- }
-);
-```
-
-
-
-
-
-A successful response provides your app with an access token. Now your app can issue outgoing payment requests to future recipients against the grant. Each request must reference the access token.
+
Example response
@@ -545,7 +162,3 @@ A successful response provides your app with an access token. Now your app can i
```
-
-:::note[Access token expiry]
-If an outgoing payment request fails because the grant's access token has expired, you can call the [Rotate Access Token API](/apis/auth-server/operations/post-token/), then use the new token in the outgoing payment request.
-:::
diff --git a/docs/src/content/docs/guides/recurring-remittance-fixed-debit.mdx b/docs/src/content/docs/guides/recurring-remittance-fixed-debit.mdx
index 985106ce..7d71d5a7 100644
--- a/docs/src/content/docs/guides/recurring-remittance-fixed-debit.mdx
+++ b/docs/src/content/docs/guides/recurring-remittance-fixed-debit.mdx
@@ -6,6 +6,12 @@ import { LinkOut } from '@interledger/docs-design-system'
import { Tabs, TabItem, Badge } from '@astrojs/starlight/components'
import Start from '/src/content/docs/partials/_grant-start-interaction.mdx'
import Finish from '/src/content/docs/partials/_grant-finish-interaction.mdx'
+import GetWalletAddress from '/src/content/docs/partials/code/guides/recurring-remittance-fixed-debit/_get-wallet-address.mdx'
+import GrantRequestIncomingPayment from '/src/content/docs/partials/code/guides/recurring-remittance-fixed-debit/_grant-request-incoming-payment.mdx'
+import CreateIncomingPaymentOpen from '/src/content/docs/partials/code/guides/recurring-remittance-fixed-debit/_create-incoming-payment-open.mdx'
+import GrantRequestOutgoingPayment from '/src/content/docs/partials/code/guides/recurring-remittance-fixed-debit/_grant-request-outgoing-payment.mdx'
+import CreateOutgoingPayment from '/src/content/docs/partials/code/guides/recurring-remittance-fixed-debit/_create-outgoing-payment.mdx'
+import RequestAGrantContinuation from '/src/content/docs/partials/code/guides/recurring-remittance-fixed-debit/_request-a-grant-continuation.mdx'
:::tip[Summary]
Learn how to send recurring remittance payments where the sender pays a fixed debit amount with each payment.
@@ -72,79 +78,7 @@ Let's assume the sender saved their wallet address to their profile settings in
Call the [Get Wallet Address API](/apis/wallet-address-server/operations/get-wallet-address) for each address.
-
-
-
-```ts wrap
-const senderWalletAddress = await client.walletAddress.get({
- url: 'https://cloudninebank.example.com/sender'
-})
-const recipientWalletAddress = await client.walletAddress.get({
- url: 'https://happylifebank.example.com/recipient'
-})
-```
-
-
-
-
-```rust wrap
-let sender_wallet_address = client.wallet_address().get("https://cloudninebank.example.com/sender").await?;
-let recipient_wallet_address = client.wallet_address().get("https://happylifebank.example.com/recipient").await?;
-```
-
-
-
-
-```php wrap
-$senderWalletAddress = $client->walletAddress()->get([
- 'url' => 'https://cloudninebank.example.com/sender'
-]);
-$recipientWalletAddress = $client->walletAddress()->get([
- 'url' => 'https://happylifebank.example.com/recipient'
-]);
-```
-
-
-
-
-
-```go wrap
-senderWalletAddress, err := client.WalletAddress.Get(context.TODO(), op.WalletAddressGetParams{
- URL: "https://cloudninebank.example.com/sender",
-})
-if err != nil {
- log.Fatalf("Error fetching sender wallet address: %v\n", err)
-}
-
-recipientWalletAddress, err := client.WalletAddress.Get(context.TODO(), op.WalletAddressGetParams{
- URL: "https://happylifebank.example.com/recipient",
-})
-if err != nil {
- log.Fatalf("Error fetching recipient wallet address: %v\n", err)
-}
-```
-
-
-
-
-
-```java wrap
-var senderWalletAddress = client.walletAddress().get("https://cloudninebank.example.com/sender");
-var recipientWalletAddress = client.walletAddress().get("https://happylifebank.example.com/recipient");
-```
-
-
-
-
-
-```csharp wrap
-var senderWalletAddress = await client.GetWalletAddressAsync("https://cloudninebank.example.com/sender");
-var recipientWalletAddress = await client.GetWalletAddressAsync("https://happylifebank.example.com/recipient");
-```
-
-
-
-
+
Example responses
@@ -181,129 +115,7 @@ Use the recipient's `authServer` details, received in Step 1, to call the
-
-
-```ts wrap
-const recipientIncomingPaymentGrant = await client.grant.request(
- {
- url: recipientWalletAddress.authServer
- },
- {
- access_token: {
- access: [
- {
- type: 'incoming-payment',
- actions: ['create']
- }
- ]
- }
- }
-)
-```
-
-
-
-
-```rust wrap
-use open_payments::types::{AccessTokenRequest, AccessItem, IncomingPaymentAction, GrantRequest};
-let incoming_access = AccessTokenRequest {
- access: vec![AccessItem::IncomingPayment { actions: vec![IncomingPaymentAction::Create], identifier: None }],
-};
-let incoming_grant_request = GrantRequest::new(incoming_access, None);
-let recipient_incoming_payment_grant = client
- .grant()
- .request(&recipient_wallet_address.auth_server, &incoming_grant_request)
- .await?;
-```
-
-
-
-
-
-```php wrap
-$recipientIncomingPaymentGrant = $client->grant()->request(
- [
- 'url' => $recipientWalletAddress->authServer
- ],
- [
- 'access_token' => [
- 'access' => [
- [
- 'type' => 'incoming-payment',
- 'actions' => ['create'],
- ],
- ],
- ],
- ]
-);
-```
-
-
-
-
-
-```go
-incomingAccess := as.AccessIncoming{
- Type: as.IncomingPayment,
- Actions: []as.AccessIncomingActions{as.AccessIncomingActionsCreate},
-}
-accessItem := as.AccessItem{}
-if err := accessItem.FromAccessIncoming(incomingAccess); err != nil {
- log.Fatalf("Error creating AccessItem: %v\n", err)
-}
-accessToken := struct {
- Access as.Access `json:"access"`
-}{
- Access: []as.AccessItem{accessItem},
-}
-
-recipientIncomingPaymentGrant, err := client.Grant.Request(context.TODO(), op.GrantRequestParams{
- URL: *recipientWalletAddress.AuthServer,
- RequestBody: as.GrantRequestWithAccessToken{AccessToken: accessToken},
-})
-if err != nil {
- log.Fatalf("Error requesting incoming payment grant: %v\n", err)
-}
-```
-
-
-
-
-
-```java wrap
-var recipientIncomingPaymentGrant = client.auth().grant().incomingPayment(recipientWalletAddress);
-```
-
-
-
-
-
-```csharp wrap
-var recipientIncomingPaymentGrant = await client.RequestGrantAsync(
- new RequestArgs
- {
- Url = recipientWalletAddress.AuthServer,
- },
- new GrantCreateBody
- {
- AccessToken = new AccessToken
- {
- Access =
- [
- new IncomingAccess
- {
- Actions = [Actions.Create]
- }
- ]
- }
- }
-);
-```
-
-
-
-
+
Example response
@@ -339,107 +151,7 @@ Use the access token returned in the previous response to call the
-
-
-```ts wrap
-const recipientIncomingPayment = await client.incomingPayment.create(
- {
- url: recipientWalletAddress.resourceServer,
- accessToken: recipientIncomingPaymentGrant.access_token.value
- },
- {
- walletAddress: recipientWalletAddress.id
- }
-)
-```
-
-
-
-
-```rust wrap
-use open_payments::types::IncomingPaymentRequest;
-let incoming_request = IncomingPaymentRequest {
- wallet_address: recipient_wallet_address.id.clone(),
- incoming_amount: None,
- expires_at: None,
- metadata: None,
-};
-let recipient_incoming_payment = client
- .incoming_payments()
- .create(
- &recipient_wallet_address.resource_server,
- &incoming_request,
- Some(&recipient_incoming_payment_grant.access_token.value),
- )
- .await?;
-```
-
-
-
-
-
-```php wrap
-$recipientIncomingPayment = $client->incomingPayment()->create(
- [
- 'url' => $recipientWalletAddress->resourceServer,
- 'accessToken' => $recipientIncomingPaymentGrant->access_token->value
- ],
- [
- 'walletAddress' => $recipientWalletAddress->id
- ]
-);
-```
-
-
-
-
-
-```go wrap
-recipientIncomingPayment, err := client.IncomingPayment.Create(context.TODO(), op.IncomingPaymentCreateParams{
- BaseURL: *recipientWalletAddress.ResourceServer,
- AccessToken: recipientIncomingPaymentGrant.AccessToken.Value,
- Payload: rs.CreateIncomingPaymentJSONBody{
- WalletAddressSchema: *recipientWalletAddress.Id,
- },
-})
-if err != nil {
- log.Fatalf("Error creating incoming payment: %v\n", err)
-}
-```
-
-
-
-
-
-```java wrap
-var recipientIncomingPayment = client.payment().createIncoming(
- recipientWalletAddress,
- recipientIncomingPaymentGrant
-);
-```
-
-
-
-
-
-```csharp wrap
-var recipientIncomingPayment = await client.CreateIncomingPaymentAsync(
- new AuthRequestArgs
- {
- Url = recipientWalletAddress.ResourceServer,
- AccessToken = recipientIncomingPaymentGrant.AccessToken.Value
- },
- new IncomingPaymentBody
- {
- WalletAddress = recipientWalletAddress.Id
- }
-);
-```
-
-
-
-
+
Example response
@@ -484,245 +196,7 @@ Because the sender will pay a fixed amount of $200 USD per month, the request mu
Outgoing payments require an interactive grant, which the sender approves once. While the grant (and its access token) is valid and within its limits (`interval` + `debitAmount`), your app can create outgoing payments without re-approval each interval. You can find more information in the [Open Payments flow](/concepts/op-flow/#outgoing-payment) and [identity providers](/identity/idp) pages.
:::
-
-
-
-```ts wrap
-const pendingSenderOutgoingPaymentGrant = await client.grant.request(
- {
- url: senderWalletAddress.authServer
- },
- {
- access_token: {
- access: [
- {
- identifier: senderWalletAddress.id,
- type: 'outgoing-payment',
- actions: ['create'],
- limits: {
- interval: 'R3/2025-10-03T23:25:00Z/P1M',
- debitAmount: {
- assetCode: 'USD',
- assetScale: 2,
- value: '20000' // $200.00 USD per interval
- }
- }
- }
- ]
- },
- 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
- }
- }
- }
-)
-```
-
-
-
-
-```rust wrap
-use open_payments::types::{
- AccessTokenRequest,
- AccessItem,
- OutgoingPaymentAction,
- LimitsOutgoing,
- Amount,
- Interval,
- InteractRequest,
- InteractFinish,
- GrantRequest,
-};
-use uuid::Uuid;
-
-let outgoing_access = AccessTokenRequest {
-access: vec![AccessItem::OutgoingPayment {
-identifier: sender_wallet_address.id.clone(),
-actions: vec![OutgoingPaymentAction::Create],
-limits: Some(LimitsOutgoing {
-receiver: None,
-debit_amount: Some(Amount {
-value: "20000".into(),
-asset_code: "USD".into(),
-asset_scale: 2,
-}),
-receive_amount: None,
-interval: Some(Interval("R3/2025-10-03T23:25:00Z/P1M".to_string())),
-}),
-}],
-};
-
-let interact = InteractRequest {
-start: vec!["redirect".to_string()],
-finish: Some(InteractFinish {
-method: "redirect".to_string(),
-uri: "https://myapp.example.com/finish/{...}".to_string(),
-nonce: Uuid::new_v4().to_string(),
-}),
-};
-
-let outgoing_grant_request = GrantRequest::new(outgoing_access, Some(interact));
-
-let pending_sender_outgoing_payment_grant = client
-.grant()
-.request(&sender_wallet_address.auth_server, &outgoing_grant_request)
-.await?;
-
-```
-
-
-
-
-
-```php wrap
-$pendingSenderOutgoingPaymentGrant = $client->grant()->request(
- [
- 'url' => $senderWalletAddress->authServer
- ],
- [
- 'access_token' => [
- 'access' => [
- [
- 'identifier' => $senderWalletAddress->id,
- 'type' => 'outgoing-payment',
- 'actions' => ['create'],
- 'limits' => [
- 'interval' => 'R3/2025-10-03T23:25:00Z/P1M',
- 'debitAmount' => [
- 'assetCode' => 'USD',
- 'assetScale' => 2,
- 'value' => '20000', // $200.00 USD per interval
- ]
- ]
- ]
- ]
- ],
- '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
- ]
- ]
- ]
-);
-```
-
-
-
-
-
-```go wrap
-interval := "R3/2025-10-03T23:25:00Z/P1M"
-limits := as.LimitsOutgoing{}
-if err := limits.FromLimitsOutgoing1(as.LimitsOutgoing1{
- Interval: &interval,
- DebitAmount: as.Amount{
- Value: "20000", // $200.00 USD per interval
- AssetCode: "USD",
- AssetScale: 2,
- },
-}); err != nil {
- log.Fatalf("Error creating limits: %v\n", err)
-}
-
-outgoingAccess := as.AccessOutgoing{
- Type: as.OutgoingPayment,
- Actions: []as.AccessOutgoingActions{as.AccessOutgoingActionsCreate},
- Identifier: *senderWalletAddress.Id,
- Limits: &limits,
-}
-outgoingAccessItem := as.AccessItem{}
-if err := outgoingAccessItem.FromAccessOutgoing(outgoingAccess); err != nil {
- log.Fatalf("Error creating AccessItem: %v\n", err)
-}
-outgoingAccessToken := struct {
- Access as.Access `json:"access"`
-}{
- Access: []as.AccessItem{outgoingAccessItem},
-}
-interact := &as.InteractRequest{
- Start: []as.InteractRequestStart{as.InteractRequestStartRedirect},
- Finish: &as.InteractRequestFinish{
- Method: as.Redirect,
- Uri: "https://myapp.example.com/finish/{...}", // where to redirect your user after they've completed the interaction
- Nonce: NONCE,
- },
-}
-
-pendingSenderOutgoingPaymentGrant, err := client.Grant.Request(context.TODO(), op.GrantRequestParams{
- URL: *senderWalletAddress.AuthServer,
- RequestBody: as.GrantRequestWithAccessToken{
- AccessToken: outgoingAccessToken,
- Interact: interact,
- },
-})
-if err != nil {
- log.Fatalf("Error requesting outgoing payment grant: %v\n", err)
-}
-```
-
-
-
-
-
-```java wrap
-// Build an outgoing payment grant with a fixed debit amount and interval using the Java SDK types.
-// See the Java SDK docs for constructing a LimitsOutgoing object with debitAmount and interval.
-var pendingSenderOutgoingPaymentGrant = client.auth().grant().outgoingPayment(senderWalletAddress);
-```
-
-
-
-
-
-```csharp wrap
-var pendingSenderOutgoingPaymentGrant = await client.RequestGrantAsync(
- new RequestArgs
- {
- Url = senderWalletAddress.AuthServer,
- },
- new GrantCreateBodyWithInteract
- {
- AccessToken = new AccessToken
- {
- Access =
- [
- new OutgoingAccess
- {
- Identifier = senderWalletAddress.Id,
- Actions = [Actions.Create],
- Limits = new OutgoingAccessLimits
- {
- DebitAmount = new AuthAmount("20000", "USD", 2),
- Interval = "R3/2025-10-03T23:25:00Z/P1M"
- }
- }
- ]
- },
- Interact = new InteractRequest
- {
- Start = [Start.Redirect],
- Finish = new Finish
- {
- Method = FinishMethod.Redirect,
- Uri = new Uri(
- "https://localhost"), // where to redirect your user after they've completed the interaction
- Nonce = NONCE
- }
- }
- }
-);
-```
-
-
-
-
+
Example response
@@ -784,107 +258,7 @@ Issue the request to the `continue.uri` provided in the initial outgoing payment
Include the `interact_ref` returned in the redirect URI's query parameters.
-
-
-
-```ts wrap
-const senderOutgoingPaymentGrant = await client.grant.continue(
- {
- url: pendingSenderOutgoingPaymentGrant.continue.uri,
- accessToken: pendingSenderOutgoingPaymentGrant.continue.access_token.value
- },
- {
- interact_ref: interactRef
- }
-)
-```
-
-
-
-
-```rust wrap
-use open_payments::types::GrantResponse;
-let (continue_uri, continue_token) = match &pending_sender_outgoing_payment_grant {
- GrantResponse::WithInteraction { continue_, .. } | GrantResponse::WithToken { continue_, .. } => {
- (&continue_.uri, &continue_.access_token.value)
- }
-};
-let sender_outgoing_payment_grant = client
- .grant()
- .continue_grant(
- continue_uri,
- &interact_ref,
- Some(continue_token),
- )
- .await?;
-```
-
-
-
-
-
-```php wrap
-$senderOutgoingPaymentGrant = $client->grant()->continue(
- [
- 'url' => $pendingSenderOutgoingPaymentGrant->continue->uri,
- 'accessToken' => $pendingSenderOutgoingPaymentGrant->continue->access_token->value
- ],
- [
- 'interact_ref' => $interactRef
- ]
-);
-```
-
-
-
-
-
-```go wrap
-senderOutgoingPaymentGrant, err := client.Grant.Continue(context.TODO(), op.GrantContinueParams{
- URL: pendingSenderOutgoingPaymentGrant.Continue.Uri,
- AccessToken: pendingSenderOutgoingPaymentGrant.Continue.AccessToken.Value,
- InteractRef: INTERACT_REF,
-})
-if err != nil {
- log.Fatalf("Error continuing grant: %v\n", err)
-}
-```
-
-
-
-
-
-```java wrap
-var senderOutgoingPaymentGrant = client.grant().continueRequest(
- GrantContinueOptions.builder()
- .url(pendingSenderOutgoingPaymentGrant.getContinue().getUri())
- .accessToken(pendingSenderOutgoingPaymentGrant.getContinue().getAccessToken().getValue())
- .interactRef(interactRef)
- .build()
-);
-```
-
-
-
-
-
-```csharp wrap
-var senderOutgoingPaymentGrant = await client.ContinueGrantAsync(
- new AuthRequestArgs
- {
- Url = pendingSenderOutgoingPaymentGrant.Continue.Uri,
- AccessToken = pendingSenderOutgoingPaymentGrant.Continue.AccessToken.Value
- },
- new GrantContinueBody
- {
- InteractRef = interactRef
- }
-);
-```
-
-
-
-
+
Example response
@@ -927,137 +301,7 @@ The following shows an example response from the sender's wallet provider.
Use the access token returned in the outgoing payment grant continuation response (Step 7) to call the [Create Outgoing Payment API](/apis/resource-server/operations/create-outgoing-payment/). Create this payment by referencing the new `incomingPayment` URL and the fixed `debitAmount`.
-
-
-
-```ts wrap
-const senderOutgoingPayment = await client.outgoingPayment.create(
- {
- url: senderWalletAddress.resourceServer,
- accessToken: senderOutgoingPaymentGrant.access_token.value
- },
- {
- walletAddress: senderWalletAddress.id,
- incomingPayment: recipientIncomingPayment.id,
- debitAmount: {
- assetCode: 'USD',
- assetScale: 2,
- value: '20000'
- }
- }
-)
-```
-
-
-
-
-```rust wrap
-use open_payments::types::{OutgoingPaymentRequest, Amount};
-let outgoing_request = OutgoingPaymentRequest::FromIncomingPayment {
- wallet_address: sender_wallet_address.id.clone(),
- incoming_payment_id: recipient_incoming_payment.id.clone(),
- debit_amount: Amount {
- value: "20000".into(),
- asset_code: "USD".into(),
- asset_scale: 2,
- },
- metadata: None,
-};
-let sender_outgoing_payment = client
- .outgoing_payments()
- .create(
- &sender_wallet_address.resource_server,
- &outgoing_request,
- Some(&sender_outgoing_payment_grant.access_token.value),
- )
- .await?;
-```
-
-
-
-
-
-```php wrap
-$senderOutgoingPayment = $client->outgoingPayment()->create(
- [
- 'url' => $senderWalletAddress->resourceServer,
- 'accessToken' => $senderOutgoingPaymentGrant->access_token->value
- ],
- [
- 'walletAddress' => $senderWalletAddress->id,
- 'incomingPayment' => $recipientIncomingPayment->id,
- 'debitAmount' => [
- 'assetCode' => 'USD',
- 'assetScale' => 2,
- 'value' => '20000'
- ],
- ]
- );
-```
-
-
-
-
-
-```go wrap
-var outgoingPayload rs.CreateOutgoingPaymentRequest
-if err := outgoingPayload.FromCreateOutgoingPaymentWithoutQuote(rs.CreateOutgoingPaymentWithoutQuote{
- WalletAddressSchema: *senderWalletAddress.Id,
- IncomingPayment: *recipientIncomingPayment.Id,
- DebitAmount: &rs.Amount{
- Value: "20000",
- AssetCode: "USD",
- AssetScale: 2,
- },
-}); err != nil {
- log.Fatalf("Error creating payload: %v\n", err)
-}
-
-senderOutgoingPayment, err := client.OutgoingPayment.Create(context.TODO(), op.OutgoingPaymentCreateParams{
- BaseURL: *senderWalletAddress.ResourceServer,
- AccessToken: senderOutgoingPaymentGrant.AccessToken.Value,
- Payload: outgoingPayload,
-})
-if err != nil {
- log.Fatalf("Error creating outgoing payment: %v\n", err)
-}
-```
-
-
-
-
-
-```java wrap
-var senderOutgoingPayment = client.payment().createOutgoingFromIncoming(
- senderWalletAddress,
- recipientIncomingPayment,
- senderOutgoingPaymentGrant
-);
-```
-
-
-
-
-
-```csharp wrap
-var senderOutgoingPayment = await client.CreateOutgoingPaymentAsync(
- new AuthRequestArgs
- {
- Url = senderWalletAddress.ResourceServer,
- AccessToken = senderOutgoingPaymentGrant.AccessToken.Value
- },
- new OutgoingPaymentBodyFromIncomingPayment
- {
- WalletAddress = senderWalletAddress.Id,
- IncomingPayment = recipientIncomingPayment.Id,
- DebitAmount = new Amount("20000", "USD", 2)
- }
-);
-```
-
-
-
-
+
Example response
diff --git a/docs/src/content/docs/guides/recurring-remittance-fixed-receive.mdx b/docs/src/content/docs/guides/recurring-remittance-fixed-receive.mdx
index ec107e70..5c2d94ad 100644
--- a/docs/src/content/docs/guides/recurring-remittance-fixed-receive.mdx
+++ b/docs/src/content/docs/guides/recurring-remittance-fixed-receive.mdx
@@ -6,6 +6,14 @@ import { LinkOut } from '@interledger/docs-design-system'
import { Tabs, TabItem, Badge } from '@astrojs/starlight/components'
import Start from '/src/content/docs/partials/_grant-start-interaction.mdx'
import Finish from '/src/content/docs/partials/_grant-finish-interaction.mdx'
+import GetWalletAddress from '/src/content/docs/partials/code/guides/recurring-remittance-fixed-receive/_get-wallet-address.mdx'
+import GrantRequestIncomingPayment from '/src/content/docs/partials/code/guides/recurring-remittance-fixed-receive/_grant-request-incoming-payment.mdx'
+import CreateIncomingPayment from '/src/content/docs/partials/code/guides/recurring-remittance-fixed-receive/_create-incoming-payment.mdx'
+import GrantRequestQuote from '/src/content/docs/partials/code/guides/recurring-remittance-fixed-receive/_grant-request-quote.mdx'
+import CreateQuoteIlp from '/src/content/docs/partials/code/guides/recurring-remittance-fixed-receive/_create-quote-ilp.mdx'
+import GrantRequestOutgoingPayment from '/src/content/docs/partials/code/guides/recurring-remittance-fixed-receive/_grant-request-outgoing-payment.mdx'
+import CreateOutgoingPayment from '/src/content/docs/partials/code/guides/recurring-remittance-fixed-receive/_create-outgoing-payment.mdx'
+import RequestAGrantContinuation from '/src/content/docs/partials/code/guides/recurring-remittance-fixed-receive/_request-a-grant-continuation.mdx'
:::tip[Summary]
Learn how to send recurring remittance payments where the recipient will receive a fixed amount with each payment.
@@ -76,79 +84,7 @@ Let's assume the sender saved their wallet address to their profile settings in
Call the [Get Wallet Address API](/apis/wallet-address-server/operations/get-wallet-address) for each address.
-
-
-
-```ts wrap
-const senderWalletAddress = await client.walletAddress.get({
- url: 'https://cloudninebank.example.com/sender'
-})
-const recipientWalletAddress = await client.walletAddress.get({
- url: 'https://happylifebank.example.com/recipient'
-})
-```
-
-
-
-
-```rust wrap
-let sender_wallet_address = client.wallet_address().get("https://cloudninebank.example.com/sender").await?;
-let recipient_wallet_address = client.wallet_address().get("https://happylifebank.example.com/recipient").await?;
-```
-
-
-
-
-```php wrap
-$senderWalletAddress = $client->walletAddress()->get([
- 'url' => 'https://cloudninebank.example.com/sender'
-]);
-$recipientWalletAddress = $client->walletAddress()->get([
- 'url' => 'https://happylifebank.example.com/recipient'
-]);
-```
-
-
-
-
-
-```go wrap
-senderWalletAddress, err := client.WalletAddress.Get(context.TODO(), op.WalletAddressGetParams{
- URL: "https://cloudninebank.example.com/sender",
-})
-if err != nil {
- log.Fatalf("Error fetching sender wallet address: %v\n", err)
-}
-
-recipientWalletAddress, err := client.WalletAddress.Get(context.TODO(), op.WalletAddressGetParams{
- URL: "https://happylifebank.example.com/recipient",
-})
-if err != nil {
- log.Fatalf("Error fetching recipient wallet address: %v\n", err)
-}
-```
-
-
-
-
-
-```java wrap
-var senderWalletAddress = client.walletAddress().get("https://cloudninebank.example.com/sender");
-var recipientWalletAddress = client.walletAddress().get("https://happylifebank.example.com/recipient");
-```
-
-
-
-
-
-```csharp wrap
-var senderWalletAddress = await client.GetWalletAddressAsync("https://cloudninebank.example.com/sender");
-var recipientWalletAddress = await client.GetWalletAddressAsync("https://happylifebank.example.com/recipient");
-```
-
-
-
-
+
Example responses
@@ -194,245 +130,7 @@ Because the sender wants the recipient to receive a fixed amount of $4,000 MXN e
Outgoing payments require an interactive grant, which the sender approves once. While the grant (and its access token) is valid and within its limits (`interval` + `receiveAmount`), your app can create outgoing payments without re-approval each interval. You can find more information in the [Open Payments flow](/concepts/op-flow/#outgoing-payment) and [identity providers](/identity/idp) pages.
:::
-
-
-
-```ts wrap
-const pendingSenderOutgoingPaymentGrant = await client.grant.request(
- {
- url: senderWalletAddress.authServer
- },
- {
- access_token: {
- access: [
- {
- identifier: senderWalletAddress.id,
- type: 'outgoing-payment',
- actions: ['create'],
- limits: {
- interval: 'R3/2025-10-03T23:25:00Z/P1M',
- receiveAmount: {
- assetCode: 'MXN',
- assetScale: 2,
- value: '400000'
- }
- }
- }
- ]
- },
- 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
- }
- }
- }
-)
-```
-
-
-
-
-```rust wrap
-use open_payments::types::{
- AccessTokenRequest,
- AccessItem,
- OutgoingPaymentAction,
- LimitsOutgoing,
- Amount,
- Interval,
- InteractRequest,
- InteractFinish,
- GrantRequest,
-};
-use uuid::Uuid;
-
-let outgoing_access = AccessTokenRequest {
-access: vec![AccessItem::OutgoingPayment {
-identifier: sender_wallet_address.id.clone(),
-actions: vec![OutgoingPaymentAction::Create],
-limits: Some(LimitsOutgoing {
-receiver: None,
-debit_amount: None,
-receive_amount: Some(Amount {
-value: "400000".into(),
-asset_code: "MXN".into(),
-asset_scale: 2,
-}),
-interval: Some(Interval("R3/2025-10-03T23:25:00Z/P1M".to_string())),
-}),
-}],
-};
-
-let interact = InteractRequest {
-start: vec!["redirect".to_string()],
-finish: Some(InteractFinish {
-method: "redirect".to_string(),
-uri: "https://myapp.example.com/finish/{...}".to_string(),
-nonce: Uuid::new_v4().to_string(),
-}),
-};
-
-let outgoing_grant_request = GrantRequest::new(outgoing_access, Some(interact));
-
-let pending_sender_outgoing_payment_grant = client
-.grant()
-.request(&sender_wallet_address.auth_server, &outgoing_grant_request)
-.await?;
-
-```
-
-
-
-
-
-```php wrap
-$pendingSenderOutgoingPaymentGrant = $client->grant()->request(
- [
- 'url' => $senderWalletAddress->authServer
- ],
- [
- 'access_token' => [
- 'access' => [
- [
- 'identifier' => $senderWalletAddress->id,
- 'type' => 'outgoing-payment',
- 'actions' => ['create'],
- 'limits' => [
- 'interval' => 'R3/2025-10-03T23:25:00Z/P1M',
- 'receiveAmount' => [
- 'assetCode' => 'MXN',
- 'assetScale' => 2,
- 'value' => '400000',
- ]
- ]
- ]
- ]
- ],
- '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
- ]
- ]
- ]
-);
-```
-
-
-
-
-
-```go wrap
-interval := "R3/2025-10-03T23:25:00Z/P1M"
-limits := as.LimitsOutgoing{}
-if err := limits.FromLimitsOutgoing2(as.LimitsOutgoing2{
- Interval: &interval,
- ReceiveAmount: as.Amount{
- Value: "400000",
- AssetCode: "MXN",
- AssetScale: 2,
- },
-}); err != nil {
- log.Fatalf("Error creating limits: %v\n", err)
-}
-
-outgoingAccess := as.AccessOutgoing{
- Type: as.OutgoingPayment,
- Actions: []as.AccessOutgoingActions{as.AccessOutgoingActionsCreate},
- Identifier: *senderWalletAddress.Id,
- Limits: &limits,
-}
-outgoingAccessItem := as.AccessItem{}
-if err := outgoingAccessItem.FromAccessOutgoing(outgoingAccess); err != nil {
- log.Fatalf("Error creating AccessItem: %v\n", err)
-}
-outgoingAccessToken := struct {
- Access as.Access `json:"access"`
-}{
- Access: []as.AccessItem{outgoingAccessItem},
-}
-interact := &as.InteractRequest{
- Start: []as.InteractRequestStart{as.InteractRequestStartRedirect},
- Finish: &as.InteractRequestFinish{
- Method: as.Redirect,
- Uri: "https://myapp.example.com/finish/{...}",
- Nonce: NONCE,
- },
-}
-
-pendingSenderOutgoingPaymentGrant, err := client.Grant.Request(context.TODO(), op.GrantRequestParams{
- URL: *senderWalletAddress.AuthServer,
- RequestBody: as.GrantRequestWithAccessToken{
- AccessToken: outgoingAccessToken,
- Interact: interact,
- },
-})
-if err != nil {
- log.Fatalf("Error requesting outgoing payment grant: %v\n", err)
-}
-```
-
-
-
-
-
-```java wrap
-// Create an outgoing payment grant with a fixed receive amount and interval using the Java SDK types.
-// See the Java SDK docs for constructing a LimitsOutgoing object with receiveAmount and interval.
-var pendingSenderOutgoingPaymentGrant = client.auth().grant().outgoingPayment(senderWalletAddress);
-```
-
-
-
-
-
-```csharp wrap
-var pendingSenderOutgoingPaymentGrant = await client.RequestGrantAsync(
- new RequestArgs
- {
- Url = senderWalletAddress.AuthServer,
- },
- new GrantCreateBodyWithInteract
- {
- AccessToken = new AccessToken
- {
- Access =
- [
- new OutgoingAccess
- {
- Identifier = senderWalletAddress.Id,
- Actions = [Actions.Create],
- Limits = new OutgoingAccessLimits
- {
- DebitAmount = new AuthAmount("400000", "MXN", 2),
- Interval = "R3/2025-10-03T23:25:00Z/P1M"
- }
- }
- ]
- },
- Interact = new InteractRequest
- {
- Start = [Start.Redirect],
- Finish = new Finish
- {
- Method = FinishMethod.Redirect,
- Uri = new Uri(
- "https://localhost"), // where to redirect your user after they've completed the interaction
- Nonce = NONCE
- }
- }
- }
-);
-```
-
-
-
-
+
Example response
@@ -494,107 +192,7 @@ Issue the request to the `continue.uri` provided in the initial outgoing payment
Include the `interact_ref` returned in the redirect URI's query parameters.
-
-
-
-```ts wrap
-const senderOutgoingPaymentGrant = await client.grant.continue(
- {
- url: pendingSenderOutgoingPaymentGrant.continue.uri,
- accessToken: pendingSenderOutgoingPaymentGrant.continue.access_token.value
- },
- {
- interact_ref: interactRef
- }
-)
-```
-
-
-
-
-```rust wrap
-use open_payments::types::GrantResponse;
-let (continue_uri, continue_token) = match &pending_sender_outgoing_payment_grant {
- GrantResponse::WithInteraction { continue_, .. } | GrantResponse::WithToken { continue_, .. } => {
- (&continue_.uri, &continue_.access_token.value)
- }
-};
-let sender_outgoing_payment_grant = client
- .grant()
- .continue_grant(
- continue_uri,
- &interact_ref,
- Some(continue_token),
- )
- .await?;
-```
-
-
-
-
-
-```php wrap
-$senderOutgoingPaymentGrant = $client->grant()->continue(
- [
- 'url' => $pendingSenderOutgoingPaymentGrant->continue->uri,
- 'accessToken' => $pendingSenderOutgoingPaymentGrant->continue->access_token->value
- ],
- [
- 'interact_ref' => $interactRef
- ]
-);
-```
-
-
-
-
-
-```go wrap
-senderOutgoingPaymentGrant, err := client.Grant.Continue(context.TODO(), op.GrantContinueParams{
- URL: pendingSenderOutgoingPaymentGrant.Continue.Uri,
- AccessToken: pendingSenderOutgoingPaymentGrant.Continue.AccessToken.Value,
- InteractRef: INTERACT_REF,
-})
-if err != nil {
- log.Fatalf("Error continuing grant: %v\n", err)
-}
-```
-
-
-
-
-
-```java wrap
-var senderOutgoingPaymentGrant = client.grant().continueRequest(
- GrantContinueOptions.builder()
- .url(pendingSenderOutgoingPaymentGrant.getContinue().getUri())
- .accessToken(pendingSenderOutgoingPaymentGrant.getContinue().getAccessToken().getValue())
- .interactRef(interactRef)
- .build()
-);
-```
-
-
-
-
-
-```csharp wrap
-var senderOutgoingPaymentGrant = await client.ContinueGrantAsync(
- new AuthRequestArgs
- {
- Url = pendingSenderOutgoingPaymentGrant.Continue.Uri,
- AccessToken = pendingSenderOutgoingPaymentGrant.Continue.AccessToken.Value
- },
- new GrantContinueBody
- {
- InteractRef = interactRef
- }
-);
-```
-
-
-
-
+
Example response
@@ -639,128 +237,7 @@ Use the recipient's `authServer` details, received in Step 1, to call the
-
-
-```ts wrap
-const recipientIncomingPaymentGrant = await client.grant.request(
- {
- url: recipientWalletAddress.authServer
- },
- {
- access_token: {
- access: [
- {
- type: 'incoming-payment',
- actions: ['create']
- }
- ]
- }
- }
-)
-```
-
-
-
-
-```rust wrap
-use open_payments::types::{AccessTokenRequest, AccessItem, IncomingPaymentAction, GrantRequest};
-let incoming_access = AccessTokenRequest {
- access: vec![AccessItem::IncomingPayment { actions: vec![IncomingPaymentAction::Create], identifier: None }],
-};
-let incoming_grant_request = GrantRequest::new(incoming_access, None);
-let recipient_incoming_payment_grant = client
- .grant()
- .request(&recipient_wallet_address.auth_server, &incoming_grant_request)
- .await?;
-```
-
-
-
-
-
-```php wrap
-$recipientIncomingPaymentGrant = $client->grant()->request(
- [
- 'url' => $recipientWalletAddress->authServer
- ],
- [
- 'access_token' => [
- 'access' => [
- [
- 'type' => 'incoming-payment',
- 'actions' => ['create'],
- ],
- ],
- ],
- ]
-);
-```
-
-
-
-
-
-```go wrap
-incomingAccess := as.AccessIncoming{
- Type: as.IncomingPayment,
- Actions: []as.AccessIncomingActions{as.AccessIncomingActionsCreate},
-}
-accessItem := as.AccessItem{}
-if err := accessItem.FromAccessIncoming(incomingAccess); err != nil {
- log.Fatalf("Error creating AccessItem: %v\n", err)
-}
-accessToken := struct {
- Access as.Access `json:"access"`
-}{
- Access: []as.AccessItem{accessItem},
-}
-recipientIncomingPaymentGrant, err := client.Grant.Request(context.TODO(), op.GrantRequestParams{
- URL: *recipientWalletAddress.AuthServer,
- RequestBody: as.GrantRequestWithAccessToken{AccessToken: accessToken},
-})
-if err != nil {
- log.Fatalf("Error requesting incoming payment grant: %v\n", err)
-}
-```
-
-
-
-
-
-```java wrap
-var recipientIncomingPaymentGrant = client.auth().grant().incomingPayment(recipientWalletAddress);
-```
-
-
-
-
-
-```csharp wrap
-var recipientIncomingPaymentGrant = await client.RequestGrantAsync(
- new RequestArgs
- {
- Url = recipientWalletAddress.AuthServer,
- },
- new GrantCreateBody
- {
- AccessToken = new AccessToken
- {
- Access =
- [
- new IncomingAccess
- {
- Actions = [Actions.Create],
- }
- ]
- }
- }
-);
-```
-
-
-
-
+
Example response
@@ -796,107 +273,7 @@ Use the access token returned in the previous response to call the
-
-
-```ts wrap
-const recipientIncomingPayment = await client.incomingPayment.create(
- {
- url: recipientWalletAddress.resourceServer,
- accessToken: recipientIncomingPaymentGrant.access_token.value
- },
- {
- walletAddress: recipientWalletAddress.id
- }
-)
-```
-
-
-
-
-```rust wrap
-use open_payments::types::IncomingPaymentRequest;
-let incoming_request = IncomingPaymentRequest {
- wallet_address: recipient_wallet_address.id.clone(),
- incoming_amount: None,
- expires_at: None,
- metadata: None,
-};
-let recipient_incoming_payment = client
- .incoming_payments()
- .create(
- &recipient_wallet_address.resource_server,
- &incoming_request,
- Some(&recipient_incoming_payment_grant.access_token.value),
- )
- .await?;
-```
-
-
-
-
-
-```php wrap
-$recipientIncomingPayment = $client->incomingPayment()->create(
- [
- 'url' => $recipientWalletAddress->resourceServer,
- 'accessToken' => $recipientIncomingPaymentGrant->access_token->value
- ],
- [
- 'walletAddress' => $recipientWalletAddress->id,
- ]
-);
-```
-
-
-
-
-
-```go wrap
-recipientIncomingPayment, err := client.IncomingPayment.Create(context.TODO(), op.IncomingPaymentCreateParams{
- BaseURL: *recipientWalletAddress.ResourceServer,
- AccessToken: recipientIncomingPaymentGrant.AccessToken.Value,
- Payload: rs.CreateIncomingPaymentJSONBody{
- WalletAddressSchema: *recipientWalletAddress.Id,
- },
-})
-if err != nil {
- log.Fatalf("Error creating incoming payment: %v\n", err)
-}
-```
-
-
-
-
-
-```java wrap
-var recipientIncomingPayment = client.payment().createIncoming(
- recipientWalletAddress,
- recipientIncomingPaymentGrant
-);
-```
-
-
-
-
-
-```csharp wrap
-var recipientIncomingPayment = await client.CreateIncomingPaymentAsync(
- new AuthRequestArgs
- {
- Url = recipientWalletAddress.ResourceServer,
- AccessToken = recipientIncomingPaymentGrant.AccessToken.Value
- },
- new IncomingPaymentBody
- {
- WalletAddress = recipientWalletAddress.Id
- }
-);
-```
-
-
-
-
+
Example response
@@ -932,128 +309,7 @@ Use the sender's `authServer` details, received in Step 1, to call the
-
-
-```ts wrap
-const senderQuoteGrant = await client.grant.request(
- {
- url: senderWalletAddress.authServer
- },
- {
- access_token: {
- access: [
- {
- type: 'quote',
- actions: ['create']
- }
- ]
- }
- }
-)
-```
-
-
-
-
-```rust wrap
-use open_payments::types::{AccessTokenRequest, AccessItem, QuoteAction, GrantRequest};
-let quote_access = AccessTokenRequest {
- access: vec![AccessItem::Quote { actions: vec![QuoteAction::Create] }],
-};
-let quote_grant_request = GrantRequest::new(quote_access, None);
-let sender_quote_grant = client
- .grant()
- .request(&sender_wallet_address.auth_server, "e_grant_request)
- .await?;
-```
-
-
-
-
-
-```php wrap
-$senderQuoteGrant = $client->grant()->request(
- [
- 'url' => $senderWalletAddress->authServer
- ],
- [
- 'access_token' => [
- 'access' => [
- [
- 'type' => 'quote',
- 'actions' => ['create']
- ]
- ]
- ]
- ]
-);
-```
-
-
-
-
-
-```go wrap
-quoteAccess := as.AccessQuote{
- Type: as.Quote,
- Actions: []as.AccessQuoteActions{as.Create},
-}
-quoteAccessItem := as.AccessItem{}
-if err := quoteAccessItem.FromAccessQuote(quoteAccess); err != nil {
- log.Fatalf("Error creating AccessItem: %v\n", err)
-}
-quoteAccessToken := struct {
- Access as.Access `json:"access"`
-}{
- Access: []as.AccessItem{quoteAccessItem},
-}
-senderQuoteGrant, err := client.Grant.Request(context.TODO(), op.GrantRequestParams{
- URL: senderWalletAddress.AuthServer,
- RequestBody: as.GrantRequestWithAccessToken{AccessToken: quoteAccessToken},
-})
-if err != nil {
- log.Fatalf("Error requesting quote grant: %v\n", err)
-}
-```
-
-
-
-
-
-```java wrap
-var senderQuoteGrant = client.auth().grant().quote(senderWalletAddress);
-```
-
-
-
-
-
-```csharp wrap
-var senderQuoteGrant = await client.RequestGrantAsync(
- new RequestArgs
- {
- Url = senderWalletAddress.AuthServer,
- },
- new GrantCreateBody
- {
- AccessToken = new AccessToken
- {
- Access =
- [
- new QuoteAccess
- {
- Actions = [Actions.Create],
- }
- ]
- }
- }
-);
-```
-
-
-
-
+
Example response
@@ -1091,147 +347,7 @@ This call requests that a quote resource be created on the sender's wallet accou
The `receiveAmount` specifies that the recipient will receive exactly $4,000 MXN.
-
-
-
-```ts wrap
-const senderQuote = await client.quote.create(
- {
- url: senderWalletAddress.resourceServer,
- accessToken: senderQuoteGrant.access_token.value
- },
- {
- method: 'ilp',
- walletAddress: senderWalletAddress.id,
- receiver: recipientIncomingPayment.id,
- receiveAmount: {
- value: '400000',
- assetCode: 'MXN',
- assetScale: 2
- }
- }
-)
-```
-
-
-
-
-```rust wrap
-use open_payments::types::{CreateQuoteRequest, PaymentMethodType, Receiver, Amount};
-let quote_request = CreateQuoteRequest::FixedReceiveAmountQuote {
- wallet_address: sender_wallet_address.id.clone(),
- receiver: Receiver(recipient_incoming_payment.id.clone()),
- method: PaymentMethodType::Ilp,
- receive_amount: Amount {
- value: "400000".into(),
- asset_code: "MXN".into(),
- asset_scale: 2,
- },
-};
-let sender_quote = client
- .quotes()
- .create(
- &sender_wallet_address.resource_server,
- "e_request,
- Some(&sender_quote_grant.access_token.value),
- )
- .await?;
-```
-
-
-
-
-
-```php wrap
-$senderQuote = $client->quote()->create(
- [
- 'url' => $senderWalletAddress->resourceServer,
- 'accessToken' => $senderQuoteGrant->access_token->value
- ],
- [
- 'method' => 'ilp',
- 'walletAddress' => $senderWalletAddress->id,
- 'receiver' => $recipientIncomingPayment->id,
- 'receiveAmount' => [
- 'value' => '400000',
- 'assetCode' => 'MXN',
- 'assetScale' => 2
- ]
- ]
-);
-```
-
-
-
-
-
-```go wrap
-senderQuote, err := client.Quote.Create(context.TODO(), op.QuoteCreateParams{
- BaseURL: *senderWalletAddress.ResourceServer,
- AccessToken: senderQuoteGrant.AccessToken.Value,
- Payload: rs.CreateQuoteJSONBody1{
- WalletAddressSchema: *senderWalletAddress.Id,
- Receiver: *recipientIncomingPayment.Id,
- Method: "ilp",
- ReceiveAmount: rs.Amount{
- Value: "400000",
- AssetCode: "MXN",
- AssetScale: 2,
- },
- },
-})
-if err != nil {
- log.Fatalf("Error creating quote: %v\n", err)
-}
-```
-
-
-
-
-
-```java wrap
-var senderQuote = client.quote().create(
- senderQuoteGrant.getAccess().getToken(),
- senderWalletAddress,
- recipientIncomingPayment,
- Optional.empty(),
- Optional.empty()
-);
-```
-
-
-
-
-
-```csharp wrap
-var senderQuote = await client.CreateQuoteAsync(
- new AuthRequestArgs
- {
- Url = senderWalletAddress.ResourceServer,
- AccessToken = senderQuoteGrant.AccessToken.Value
- },
- new QuoteBodyWithReceiveAmount
- {
- Method = PaymentMethod.Ilp,
- WalletAddress = senderWalletAddress.Id,
- Receiver = recipientIncomingPayment.Id,
- ReceiveAmount = new Amount("400000", "MXN", 2)
- }
-);
-```
-
-
-
-
-
-The response returns a `receiveAmount`, a `debitAmount`, and other required information.
-
-- `debitAmount` - The amount the sender must pay (in USD in our example) after currency conversion.
-- `receiveAmount` - The amount the recipient will actually receive (exactly $4,000 MXN in our example).
-
-:::note[Expiring quotes]
-Quote responses include an `expiresAt` timestamp. Create the outgoing payment before the quote expires. If creation fails because the quote expired, request a new quote and try again.
-:::
+
Example response
@@ -1261,119 +377,20 @@ The following shows an example response from the sender's wallet provider.
-### 10. Request the creation of an outgoing payment resource
-
-Use the access token returned in the outgoing payment grant continuation response (Step 5) to call the [Create Outgoing Payment API](/apis/resource-server/operations/create-outgoing-payment/).
-
-
-
-
-```ts wrap
-const senderOutgoingPayment = await client.outgoingPayment.create(
- {
- url: senderWalletAddress.resourceServer,
- accessToken: senderOutgoingPaymentGrant.access_token.value
- },
- {
- walletAddress: senderWalletAddress.id,
- quoteId: senderQuote.id
- }
-)
-```
-
-
-
-
-```rust wrap
-use open_payments::types::OutgoingPaymentRequest;
-let outgoing_request = OutgoingPaymentRequest::FromQuote {
- wallet_address: sender_wallet_address.id.clone(),
- quote_id: sender_quote.id.clone(),
- metadata: None,
-};
-let sender_outgoing_payment = client
- .outgoing_payments()
- .create(
- &sender_wallet_address.resource_server,
- &outgoing_request,
- Some(&sender_outgoing_payment_grant.access_token.value),
- )
- .await?;
-```
-
-
-
-
-```php wrap
-$senderOutgoingPayment = $client->outgoingPayment()->create(
- [
- 'url' => $senderWalletAddress->resourceServer,
- 'accessToken' => $senderOutgoingPaymentGrant->access_token->value
- ],
- [
- 'walletAddress' => $senderWalletAddress->id,
- 'quoteId' => $senderQuote->id,
- ]
-);
-```
-
-
-
-
-
-```go wrap
-var outgoingPayload rs.CreateOutgoingPaymentRequest
-if err := outgoingPayload.FromCreateOutgoingPaymentWithQuote(rs.CreateOutgoingPaymentWithQuote{
- WalletAddressSchema: *senderWalletAddress.Id,
- QuoteId: *senderQuote.Id,
-}); err != nil {
- log.Fatalf("Error creating payload: %v\n", err)
-}
-
-senderOutgoingPayment, err := client.OutgoingPayment.Create(context.TODO(), op.OutgoingPaymentCreateParams{
- BaseURL: *senderWalletAddress.ResourceServer,
- AccessToken: senderOutgoingPaymentGrant.AccessToken.Value,
- Payload: outgoingPayload,
-})
-if err != nil {
- log.Fatalf("Error creating outgoing payment: %v\n", err)
-}
-```
-
-
-
-
-
-```java wrap
-var senderOutgoingPayment = client.payment().createOutgoingFromQuote(
- senderWalletAddress,
- senderQuote,
- senderOutgoingPaymentGrant
-);
-```
+The response returns a `receiveAmount`, a `debitAmount`, and other required information.
-
+- `debitAmount` - The amount the sender must pay (in USD in our example) after currency conversion.
+- `receiveAmount` - The amount the recipient will actually receive (exactly $4,000 MXN in our example).
-
+:::note[Expiring quotes]
+Quote responses include an `expiresAt` timestamp. Create the outgoing payment before the quote expires. If creation fails because the quote expired, request a new quote and try again.
+:::
-```csharp wrap
-var senderOutgoingPayment = await client.CreateOutgoingPaymentAsync(
- new AuthRequestArgs
- {
- Url = senderWalletAddress.ResourceServer,
- AccessToken = senderOutgoingPaymentGrant.AccessToken.Value
- },
- new OutgoingPaymentBodyFromQuote
- {
- WalletAddress = senderWalletAddress.Id,
- QuoteId = senderQuote.Id,
- }
-);
-```
+### 10. Request the creation of an outgoing payment resource
-
+Use the access token returned in the outgoing payment grant continuation response (Step 5) to call the [Create Outgoing Payment API](/apis/resource-server/operations/create-outgoing-payment/).
-
+
Example response
diff --git a/docs/src/content/docs/guides/recurring-subscription-incoming-amount.mdx b/docs/src/content/docs/guides/recurring-subscription-incoming-amount.mdx
index cb99c50c..44bf89d3 100644
--- a/docs/src/content/docs/guides/recurring-subscription-incoming-amount.mdx
+++ b/docs/src/content/docs/guides/recurring-subscription-incoming-amount.mdx
@@ -6,6 +6,14 @@ import { LinkOut } from '@interledger/docs-design-system'
import { Tabs, TabItem, Badge } from '@astrojs/starlight/components'
import Start from '/src/content/docs/partials/_grant-start-interaction.mdx'
import Finish from '/src/content/docs/partials/_grant-finish-interaction.mdx'
+import GetWalletAddress from '/src/content/docs/partials/code/guides/recurring-subscription-incoming-amount/_get-wallet-address.mdx'
+import GrantRequestIncomingPayment from '/src/content/docs/partials/code/guides/recurring-subscription-incoming-amount/_grant-request-incoming-payment.mdx'
+import CreateIncomingPayment from '/src/content/docs/partials/code/guides/recurring-subscription-incoming-amount/_create-incoming-payment.mdx'
+import GrantRequestQuote from '/src/content/docs/partials/code/guides/recurring-subscription-incoming-amount/_grant-request-quote.mdx'
+import CreateQuote from '/src/content/docs/partials/code/guides/recurring-subscription-incoming-amount/_create-quote.mdx'
+import GrantRequestOutgoingPayment from '/src/content/docs/partials/code/guides/recurring-subscription-incoming-amount/_grant-request-outgoing-payment.mdx'
+import CreateOutgoingPayment from '/src/content/docs/partials/code/guides/recurring-subscription-incoming-amount/_create-outgoing-payment.mdx'
+import RequestAGrantContinuation from '/src/content/docs/partials/code/guides/recurring-subscription-incoming-amount/_request-a-grant-continuation.mdx'
:::tip[Summary]
Learn how to set up recurring subscription payments where the service provider receives a fixed amount at regular intervals.
@@ -74,79 +82,7 @@ Let's assume the customer has already provided their wallet address when they si
Call the [Get Wallet Address API](/apis/wallet-address-server/operations/get-wallet-address) for each address.
-
-
-
-```ts
-const customerWalletAddress = await client.walletAddress.get({
- url: 'https://cloudninebank.example.com/customer'
-})
-const serviceProviderWalletAddress = await client.walletAddress.get({
- url: 'https://happylifebank.example.com/service-provider'
-})
-```
-
-
-
-
-```rust wrap
-let customer_wallet_address = client.wallet_address().get("https://cloudninebank.example.com/customer").await?;
-let service_provider_wallet_address = client.wallet_address().get("https://happylifebank.example.com/service-provider").await?;
-```
-
-
-
-
-```php wrap
-$customerWalletAddress = $client->walletAddress()->get([
- 'url' => 'https://cloudninebank.example.com/customer'
-]);
-$serviceProviderWalletAddress = $client->walletAddress()->get([
- 'url' => 'https://happylifebank.example.com/service-provider'
-]);
-```
-
-
-
-
-
-```go wrap
-customerWalletAddress, err := client.WalletAddress.Get(context.TODO(), op.WalletAddressGetParams{
- URL: "https://cloudninebank.example.com/customer",
-})
-if err != nil {
- log.Fatalf("Error fetching customer wallet address: %v\n", err)
-}
-
-serviceProviderWalletAddress, err := client.WalletAddress.Get(context.TODO(), op.WalletAddressGetParams{
- URL: "https://happylifebank.example.com/service-provider",
-})
-if err != nil {
- log.Fatalf("Error fetching service provider wallet address: %v\n", err)
-}
-```
-
-
-
-
-
-```java wrap
-var customerWalletAddress = client.walletAddress().get("https://cloudninebank.example.com/customer");
-var serviceProviderWalletAddress = client.walletAddress().get("https://happylifebank.example.com/service-provider");
-```
-
-
-
-
-
-```csharp wrap
-var customerWalletAddress = await client.GetWalletAddressAsync("https://cloudninebank.example.com/customer");
-var serviceProviderWalletAddress = await client.GetWalletAddressAsync("https://happylifebank.example.com/service-provider");
-```
-
-
-
-
+
Example responses
@@ -183,128 +119,7 @@ Use the service provider's `authServer` details, received in the previous step,
This call obtains an access token that allows you to request that an incoming payment resource be created on the service provider's wallet account.
-
-
-
-```ts wrap
-const serviceProviderIncomingPaymentGrant = await client.grant.request(
- {
- url: serviceProviderWalletAddress.authServer
- },
- {
- access_token: {
- access: [
- {
- type: 'incoming-payment',
- actions: ['create']
- }
- ]
- }
- }
-)
-```
-
-
-
-
-```rust wrap
-use open_payments::types::{AccessTokenRequest, AccessItem, IncomingPaymentAction, GrantRequest};
-let incoming_access = AccessTokenRequest {
- access: vec![AccessItem::IncomingPayment { actions: vec![IncomingPaymentAction::Create], identifier: None }],
-};
-let incoming_grant_request = GrantRequest::new(incoming_access, None);
-let service_provider_incoming_payment_grant = client
- .grant()
- .request(&service_provider_wallet_address.auth_server, &incoming_grant_request)
- .await?;
-```
-
-
-
-
-```php wrap
-$serviceProviderIncomingPaymentGrant = $client->grant()->request(
- [
- 'url' => $serviceProviderWalletAddress->authServer
- ],
- [
- 'access_token' => [
- 'access' => [
- [
- 'type' => 'incoming-payment',
- 'actions' => ['create']
- ]
- ]
- ]
- ]
-);
-```
-
-
-
-
-```go wrap
-incomingAccess := as.AccessIncoming{
- Type: as.IncomingPayment,
- Actions: []as.AccessIncomingActions{as.AccessIncomingActionsCreate},
-}
-accessItem := as.AccessItem{}
-if err := accessItem.FromAccessIncoming(incomingAccess); err != nil {
- log.Fatalf("Error creating AccessItem: %v\n", err)
-}
-accessToken := struct {
- Access as.Access `json:"access"`
-}{
- Access: []as.AccessItem{accessItem},
-}
-
-serviceProviderIncomingPaymentGrant, err := client.Grant.Request(context.TODO(), op.GrantRequestParams{
- URL: *serviceProviderWalletAddress.AuthServer,
- RequestBody: as.GrantRequestWithAccessToken{AccessToken: accessToken},
-})
-if err != nil {
- log.Fatalf("Error requesting incoming payment grant: %v\n", err)
-}
-```
-
-
-
-
-```java wrap
-var serviceProviderIncomingPaymentGrant = client.auth().grant().incomingPayment(
- serviceProviderWalletAddress
-);
-```
-
-
-
-
-
-```csharp wrap
-var serviceProviderIncomingPaymentGrant = await client.RequestGrantAsync(
- new RequestArgs
- {
- Url = serviceProviderWalletAddress.AuthServer,
- },
- new GrantCreateBody
- {
- AccessToken = new AccessToken
- {
- Access =
- [
- new IncomingAccess
- {
- Actions = [Actions.Create]
- }
- ]
- }
- }
-);
-```
-
-
-
-
+
Example response
@@ -340,127 +155,7 @@ Use the access token returned in the previous response to call the
-
-
-```ts wrap
-const serviceProviderIncomingPayment = await client.incomingPayment.create(
- {
- url: serviceProviderWalletAddress.resourceServer,
- accessToken: serviceProviderIncomingPaymentGrant.access_token.value
- },
- {
- walletAddress: serviceProviderWalletAddress.id,
- incomingAmount: {
- value: '1500', // The amount the service provider expects to receive in the first payment
- assetCode: 'USD',
- assetScale: 2
- }
- }
-)
-```
-
-
-
-
-```rust wrap
-use open_payments::types::{IncomingPaymentRequest, Amount};
-let incoming_request = IncomingPaymentRequest {
- wallet_address: service_provider_wallet_address.id.clone(),
- incoming_amount: Some(Amount {
- value: "1500".into(),
- asset_code: "USD".into(),
- asset_scale: 2,
- }),
- expires_at: None,
- metadata: None,
-};
-let service_provider_incoming_payment = client
- .incoming_payments()
- .create(
- &service_provider_wallet_address.resource_server,
- &incoming_request,
- Some(&service_provider_incoming_payment_grant.access_token.value),
- )
- .await?;
-```
-
-
-
-
-```php wrap
-$serviceProviderIncomingPayment = $client->incomingPayment()->create(
- [
- 'url' => $serviceProviderWalletAddress->resourceServer,
- 'accessToken' => $serviceProviderIncomingPaymentGrant->access_token->value
- ],
- [
- 'walletAddress' => $serviceProviderWalletAddress->id,
- 'incomingAmount' => [
- 'value' => '1500', // The amount the service provider expects to receive in the first payment
- 'assetCode' => 'USD',
- 'assetScale' => 2
- ],
- ]
-);
-```
-
-
-
-
-
-```go wrap
-serviceProviderIncomingPayment, err := client.IncomingPayment.Create(context.TODO(), op.IncomingPaymentCreateParams{
- BaseURL: *serviceProviderWalletAddress.ResourceServer,
- AccessToken: serviceProviderIncomingPaymentGrant.AccessToken.Value,
- Payload: rs.CreateIncomingPaymentJSONBody{
- WalletAddressSchema: *serviceProviderWalletAddress.Id,
- IncomingAmount: &rs.Amount{
- Value: "1500",
- AssetCode: "USD",
- AssetScale: 2,
- },
- },
-})
-if err != nil {
- log.Fatalf("Error creating incoming payment: %v\n", err)
-}
-```
-
-
-
-
-
-```java wrap
-var serviceProviderIncomingPayment = client.payment().createIncoming(
- serviceProviderWalletAddress,
- serviceProviderIncomingPaymentGrant,
- BigDecimal.valueOf(15.00)
-);
-```
-
-
-
-
-
-```csharp wrap
-var serviceProviderIncomingPayment = await client.CreateIncomingPaymentAsync(
- new AuthRequestArgs
- {
- Url = serviceProviderWalletAddress.ResourceServer,
- AccessToken = serviceProviderIncomingPaymentGrant.AccessToken.Value
- },
- new IncomingPaymentBody
- {
- WalletAddress = serviceProviderWalletAddress.Id,
- IncomingAmount = new Amount("1500", "USD", 2)
- }
-);
-```
-
-
-
-
+
Example response
@@ -501,131 +196,7 @@ Use the customer's `authServer` details, received in Step 1, to call the
-
-
-```ts wrap
-const customerQuoteGrant = await client.grant.request(
- {
- url: customerWalletAddress.authServer
- },
- {
- access_token: {
- access: [
- {
- type: 'quote',
- actions: ['create']
- }
- ]
- }
- }
-)
-```
-
-
-
-
-```rust wrap
-use open_payments::types::{AccessTokenRequest, AccessItem, QuoteAction, GrantRequest};
-let quote_access = AccessTokenRequest {
- access: vec![AccessItem::Quote { actions: vec![QuoteAction::Create] }],
-};
-let quote_grant_request = GrantRequest::new(quote_access, None);
-let customer_quote_grant = client
- .grant()
- .request(&customer_wallet_address.auth_server, "e_grant_request)
- .await?;
-```
-
-
-
-
-
-```php wrap
-$customerQuoteGrant = $client->grant()->request(
- [
- 'url' => $customerWalletAddress->authServer
- ],
- [
- 'access_token' => [
- 'access' => [
- [
- 'type' => 'quote',
- 'actions' => ['create']
- ]
- ]
- ]
- ]
-);
-```
-
-
-
-
-
-```go wrap
-quoteAccess := as.AccessQuote{
- Type: as.Quote,
- Actions: []as.AccessQuoteActions{as.Create},
-}
-quoteAccessItem := as.AccessItem{}
-if err := quoteAccessItem.FromAccessQuote(quoteAccess); err != nil {
- log.Fatalf("Error creating AccessItem: %v\n", err)
-}
-quoteAccessToken := struct {
- Access as.Access `json:"access"`
-}{
- Access: []as.AccessItem{quoteAccessItem},
-}
-
-customerQuoteGrant, err := client.Grant.Request(context.TODO(), op.GrantRequestParams{
- URL: *customerWalletAddress.AuthServer,
- RequestBody: as.GrantRequestWithAccessToken{AccessToken: quoteAccessToken},
-})
-if err != nil {
- log.Fatalf("Error requesting quote grant: %v\n", err)
-}
-```
-
-
-
-
-
-```java wrap
-var customerQuoteGrant = client.auth().grant().quote(
- customerWalletAddress
-);
-```
-
-
-
-
-
-```csharp wrap
-var customerQuoteGrant = await client.RequestGrantAsync(
- new RequestArgs
- {
- Url = customerWalletAddress.AuthServer,
- },
- new GrantCreateBody
- {
- AccessToken = new AccessToken
- {
- Access =
- [
- new QuoteAccess
- {
- Actions = [Actions.Create]
- }
- ]
- }
- }
-);
-```
-
-
-
-
+
Example response
@@ -663,124 +234,7 @@ This call requests that a quote resource be created on the customer's wallet acc
The request must contain the `receiver`, which is the `id` of the service provider's incoming payment. The `id` was returned in the Create an Incoming Payment API response in Step 3.
-
-
-
-```ts wrap
-const customerQuote = await client.quote.create(
- {
- url: customerWalletAddress.resourceServer,
- accessToken: customerQuoteGrant.access_token.value
- },
- {
- method: 'ilp',
- walletAddress: customerWalletAddress.id,
- receiver: serviceProviderIncomingPayment.id
- }
-)
-```
-
-
-
-
-```rust wrap
-use open_payments::types::{CreateQuoteRequest, PaymentMethodType, Receiver};
-let quote_request = CreateQuoteRequest::NoAmountQuote {
- wallet_address: customer_wallet_address.id.clone(),
- receiver: Receiver(service_provider_incoming_payment.id.clone()),
- method: PaymentMethodType::Ilp,
-};
-let customer_quote = client
- .quotes()
- .create(
- &customer_wallet_address.resource_server,
- "e_request,
- Some(&customer_quote_grant.access_token.value),
- )
- .await?;
-```
-
-
-
-
-```php wrap
-$customerQuote = $client->quote()->create(
- [
- 'url' => $customerWalletAddress->resourceServer,
- 'accessToken' => $customerQuoteGrant->access_token->value
- ],
- [
- 'method' => 'ilp',
- 'walletAddress' => $customerWalletAddress->id,
- 'receiver' => $serviceProviderIncomingPayment->id,
- ]
-);
-```
-
-
-
-
-```go wrap
-customerQuote, err := client.Quote.Create(context.TODO(), op.QuoteCreateParams{
- BaseURL: *customerWalletAddress.ResourceServer,
- AccessToken: customerQuoteGrant.AccessToken.Value,
- Payload: rs.CreateQuoteJSONBody0{
- WalletAddressSchema: *customerWalletAddress.Id,
- Receiver: *serviceProviderIncomingPayment.Id,
- Method: "ilp",
- },
-})
-if err != nil {
- log.Fatalf("Error creating quote: %v\n", err)
-}
-```
-
-
-
-
-
-```java wrap
-var customerQuote = client.quote().create(
- customerQuoteGrant.getAccess().getToken(),
- customerWalletAddress,
- serviceProviderIncomingPayment,
- Optional.empty(),
- Optional.empty()
-);
-```
-
-
-
-
-
-```csharp wrap
-var customerQuote = await client.CreateQuoteAsync(
- new AuthRequestArgs
- {
- Url = customerWalletAddress.ResourceServer,
- AccessToken = customerQuoteGrant.AccessToken.Value
- },
- new QuoteBody
- {
- Method = PaymentMethod.Ilp,
- WalletAddress = customerWalletAddress.Id,
- Receiver = serviceProviderIncomingPayment.Id,
- }
-);
-```
-
-
-
-
-
-The response returns a `debitAmount`, a `receiveAmount`, and other required information.
-
-- `debitAmount` - The amount that will be charged to the customer.
-- `receiveAmount` - The `incomingAmount` value from the incoming payment resource
-
-:::note[Expiring quotes]
-Quote responses include an `expiresAt` timestamp. Create the outgoing payment before the quote expires. If creation fails because the quote expired, request a new quote and try again.
-:::
+
Example response
@@ -810,6 +264,15 @@ The following shows an example response from the customer's wallet provider.
+The response returns a `debitAmount`, a `receiveAmount`, and other required information.
+
+- `debitAmount` - The amount that will be charged to the customer.
+- `receiveAmount` - The `incomingAmount` value from the incoming payment resource
+
+:::note[Expiring quotes]
+Quote responses include an `expiresAt` timestamp. Create the outgoing payment before the quote expires. If creation fails because the quote expired, request a new quote and try again.
+:::
+
### 6. Request an interactive outgoing payment grant
Use the customer's `authServer` information received in Step 1 to call the [Grant Request API](/apis/auth-server/operations/post-request).
@@ -822,250 +285,7 @@ Outgoing payments require an interactive grant. This type of grant will obtain t
For recurring payments, include the `interval` property to specify how often the payment should occur. Remember that the customer wants to pay \$15 USD a month for 12 months.
-
-
-
-```ts wrap
-const pendingCustomerOutgoingPaymentGrant = await client.grant.request(
- {
- url: customerWalletAddress.authServer
- },
- {
- access_token: {
- access: [
- {
- identifier: customerWalletAddress.id,
- type: 'outgoing-payment',
- actions: ['create', 'read'],
- limits: {
- debitAmount: {
- assetCode: 'USD',
- assetScale: 2,
- value: '1500'
- },
- interval: 'R12/2025-10-14T00:03:00Z/P1M'
- }
- }
- ]
- },
- interact: {
- start: ['redirect'],
- finish: {
- method: 'redirect',
- uri: 'https://myapp.example.com/finish/{...}', // where to redirect the customer after they've completed interaction
- nonce: NONCE
- }
- }
- }
-)
-```
-
-
-
-
-```rust wrap
-use open_payments::types::{
- AccessTokenRequest,
- AccessItem,
- OutgoingPaymentAction,
- LimitsOutgoing,
- Amount,
- Interval,
- InteractRequest,
- InteractFinish,
- GrantRequest,
-};
-use uuid::Uuid;
-
-let outgoing_access = AccessTokenRequest {
-access: vec![AccessItem::OutgoingPayment {
-identifier: customer_wallet_address.id.clone(),
-actions: vec![OutgoingPaymentAction::Create, OutgoingPaymentAction::Read],
-limits: Some(LimitsOutgoing {
-receiver: None,
-debit_amount: Some(Amount {
-value: "1500".into(),
-asset_code: "USD".into(),
-asset_scale: 2,
-}),
-receive_amount: None,
-interval: Some(Interval("R12/2025-10-14T00:03:00Z/P1M".to_string())),
-}),
-}],
-};
-
-let interact = InteractRequest {
-start: vec!["redirect".to_string()],
-finish: Some(InteractFinish {
-method: "redirect".to_string(),
-uri: "https://myapp.example.com/finish/{...}".to_string(),
-nonce: Uuid::new_v4().to_string(),
-}),
-};
-
-let outgoing_grant_request = GrantRequest::new(outgoing_access, Some(interact));
-
-let pending_customer_outgoing_payment_grant = client
-.grant()
-.request(&customer_wallet_address.auth_server, &outgoing_grant_request)
-.await?;
-
-```
-
-
-
-
-
-```php wrap
-$pendingCustomerOutgoingPaymentGrant = $client->grant()->request(
- [
- 'url' => $customerWalletAddress->authServer
- ],
- [
- 'access_token' => [
- 'access' => [
- [
- 'identifier' => $customerWalletAddress->id,
- 'type' => 'outgoing-payment',
- 'actions' => ['create', 'read'],
- 'limits' => [
- 'debitAmount' => [
- 'assetCode' => 'USD',
- 'assetScale' => 2,
- 'value' => '1500',
- ],
- 'interval' => 'R12/2025-10-14T00:03:00Z/P1M'
- ]
- ]
- ]
- ],
- 'interact' => [
- 'start' => ['redirect'],
- 'finish' => [
- 'method' => 'redirect',
- 'uri' => 'https://myapp.example.com/finish/{...}', // where to redirect the customer after they've completed interaction
- 'nonce' => NONCE
- ]
- ]
- ]
-);
-```
-
-
-
-
-
-```go wrap
-interval := "R12/2025-10-14T00:03:00Z/P1M"
-limits := as.LimitsOutgoing{}
-if err := limits.FromLimitsOutgoing1(as.LimitsOutgoing1{
- Interval: &interval,
- DebitAmount: as.Amount{
- Value: "1500",
- AssetCode: "USD",
- AssetScale: 2,
- },
-}); err != nil {
- log.Fatalf("Error creating limits: %v\n", err)
-}
-
-outgoingAccess := as.AccessOutgoing{
- Type: as.OutgoingPayment,
- Actions: []as.AccessOutgoingActions{as.AccessOutgoingActionsCreate, as.AccessOutgoingActionsRead},
- Identifier: *customerWalletAddress.Id,
- Limits: &limits,
-}
-outgoingAccessItem := as.AccessItem{}
-if err := outgoingAccessItem.FromAccessOutgoing(outgoingAccess); err != nil {
- log.Fatalf("Error creating AccessItem: %v\n", err)
-}
-outgoingAccessToken := struct {
- Access as.Access `json:"access"`
-}{
- Access: []as.AccessItem{outgoingAccessItem},
-}
-interact := &as.InteractRequest{
- Start: []as.InteractRequestStart{as.InteractRequestStartRedirect},
- Finish: &as.InteractRequestFinish{
- Method: as.Redirect,
- Uri: "https://myapp.example.com/finish/{...}", // where to redirect the customer after they've completed interaction
- Nonce: NONCE,
- },
-}
-
-pendingCustomerOutgoingPaymentGrant, err := client.Grant.Request(context.TODO(), op.GrantRequestParams{
- URL: *customerWalletAddress.AuthServer,
- RequestBody: as.GrantRequestWithAccessToken{
- AccessToken: outgoingAccessToken,
- Interact: interact,
- },
-})
-if err != nil {
- log.Fatalf("Error requesting outgoing payment grant: %v\n", err)
-}
-```
-
-
-
-
-
-```java wrap
-var urlToOpen = "https://myapp.example.com/finish/{...}";
-
-var opContinueInteract = client.auth().grant().continuation(
- customerWalletAddress,
- customerQuote.getDebitAmount(),
- URI.create(urlToOpen),
- "NONCE"
-);
-```
-
-
-
-
-
-```csharp wrap
-var pendingCustomerOutgoingPaymentGrant = await client.RequestGrantAsync(
- new RequestArgs
- {
- Url = customerWalletAddress.AuthServer,
- },
- new GrantCreateBodyWithInteract
- {
- AccessToken = new AccessToken
- {
- Access =
- [
- new OutgoingAccess
- {
- Identifier = customerWalletAddress.Id,
- Actions = [Actions.Create, Actions.Read],
- Limits = new OutgoingAccessLimits
- {
- DebitAmount = new AuthAmount("1500", "USD", 2),
- Interval = "R12/2025-10-14T00:03:00Z/P1M"
- }
- }
- ]
- },
- Interact = new InteractRequest
- {
- Start = [Start.Redirect],
- Finish = new Finish
- {
- Method = FinishMethod.Redirect,
- Uri = new Uri(
- "https://localhost"), // where to redirect your user after they've completed the interaction
- Nonce = NONCE
- }
- }
- }
-);
-```
-
-
-
-
+
Example response
@@ -1123,104 +343,7 @@ Issue the request to the `continue.uri` provided in the initial outgoing payment
Include the `interact_ref` returned in the redirect URI's query parameters.
-
-
-
- ```ts wrap
- const customerOutgoingPaymentGrant = await client.grant.continue(
- {
- url: pendingCustomerOutgoingPaymentGrant.continue.uri,
- accessToken: pendingCustomerOutgoingPaymentGrant.continue.access_token.value
- },
- {
- interact_ref: interactRef
- }
- )
- ```
-
-
-
-
-```rust wrap
-use open_payments::types::GrantResponse;
-let (continue_uri, continue_token) = match &pending_customer_outgoing_payment_grant {
- GrantResponse::WithInteraction { continue_, .. } | GrantResponse::WithToken { continue_, .. } => {
- (&continue_.uri, &continue_.access_token.value)
- }
-};
-let customer_outgoing_payment_grant = client
- .grant()
- .continue_grant(
- continue_uri,
- &interact_ref,
- Some(continue_token),
- )
- .await?;
-```
-
-
-
-
-
-```php wrap
-$customerOutgoingPaymentGrant = $client->grant()->continue(
- [
- 'url' => $pendingCustomerOutgoingPaymentGrant->continue->uri,
- 'accessToken' => $pendingCustomerOutgoingPaymentGrant->continue->access_token->value
- ],
- [
- 'interact_ref' => $interactRef
- ]
-);
-```
-
-
-
-
-
-```go wrap
-customerOutgoingPaymentGrant, err := client.Grant.Continue(context.TODO(), op.GrantContinueParams{
- URL: pendingCustomerOutgoingPaymentGrant.Continue.Uri,
- AccessToken: pendingCustomerOutgoingPaymentGrant.Continue.AccessToken.Value,
- InteractRef: INTERACT_REF,
-})
-if err != nil {
- log.Fatalf("Error continuing grant: %v\n", err)
-}
-```
-
-
-
-
-
-```java wrap
-var customerOutgoingPaymentGrant = client.auth().grant().finalize(
- opContinueInteract,
- interactRef
-);
-```
-
-
-
-
-
-```csharp wrap
-var customerOutgoingPaymentGrant = await client.ContinueGrantAsync(
- new AuthRequestArgs
- {
- Url = pendingCustomerOutgoingPaymentGrant.Continue.Uri,
- AccessToken = pendingCustomerOutgoingPaymentGrant.Continue.AccessToken.Value
- },
- new GrantContinueBody
- {
- InteractRef = interactRef
- }
-);
-```
-
-
-
-
+
Example response
@@ -1265,113 +388,7 @@ Use the access token returned in Step 9 to call the
-
-
-```ts wrap
-const customerOutgoingPayment = await client.outgoingPayment.create(
- {
- url: customerWalletAddress.resourceServer,
- accessToken: customerOutgoingPaymentGrant.access_token.value
- },
- {
- walletAddress: customerWalletAddress.id,
- quoteId: customerQuote.id
- }
-)
-```
-
-
-
-
-```rust wrap
-use open_payments::types::OutgoingPaymentRequest;
-let outgoing_request = OutgoingPaymentRequest::FromQuote {
- wallet_address: customer_wallet_address.id.clone(),
- quote_id: customer_quote.id.clone(),
- metadata: None,
-};
-let customer_outgoing_payment = client
- .outgoing_payments()
- .create(
- &customer_wallet_address.resource_server,
- &outgoing_request,
- Some(&customer_outgoing_payment_grant.access_token.value),
- )
- .await?;
-```
-
-
-
-
-```php wrap
-$customerOutgoingPayment = $client->outgoingPayment()->create(
- [
- 'url' => $customerWalletAddress->resourceServer,
- 'accessToken' => $customerOutgoingPaymentGrant->access_token->value
- ],
- [
- 'walletAddress' => $customerWalletAddress->id,
- 'quoteId' => $customerQuote->id
- ]
-);
-```
-
-
-
-
-```go wrap
-var outgoingPayload rs.CreateOutgoingPaymentRequest
-if err := outgoingPayload.FromCreateOutgoingPaymentWithQuote(rs.CreateOutgoingPaymentWithQuote{
- WalletAddressSchema: *customerWalletAddress.Id,
- QuoteId: *customerQuote.Id,
-}); err != nil {
- log.Fatalf("Error creating payload: %v\n", err)
-}
-
-customerOutgoingPayment, err := client.OutgoingPayment.Create(context.TODO(), op.OutgoingPaymentCreateParams{
- BaseURL: *customerWalletAddress.ResourceServer,
- AccessToken: customerOutgoingPaymentGrant.AccessToken.Value,
- Payload: outgoingPayload,
-})
-if err != nil {
- log.Fatalf("Error creating outgoing payment: %v\n", err)
-}
-```
-
-
-
-
-```java wrap
-var customerOutgoingPayment = client.payment().createOutgoing(
- customerOutgoingPaymentGrant,
- customerWalletAddress,
- customerQuote
-);
-```
-
-
-
-
-
-```csharp wrap
-var customerOutgoingPayment = await client.CreateOutgoingPaymentAsync(
- new AuthRequestArgs
- {
- Url = customerWalletAddress.ResourceServer,
- AccessToken = customerOutgoingPaymentGrant.AccessToken.Value
- },
- new OutgoingPaymentBodyFromQuote
- {
- WalletAddress = customerWalletAddress.Id,
- QuoteId = customerQuote.Id,
- }
-);
-```
-
-
-
-
+
Example response
diff --git a/docs/src/content/docs/guides/split-payments.mdx b/docs/src/content/docs/guides/split-payments.mdx
index a9a26de5..28d90fc3 100644
--- a/docs/src/content/docs/guides/split-payments.mdx
+++ b/docs/src/content/docs/guides/split-payments.mdx
@@ -7,6 +7,14 @@ import { Tabs, TabItem, Badge } from '@astrojs/starlight/components'
import InteractionReq from '/src/content/docs/partials/_interaction-required.mdx'
import Start from '/src/content/docs/partials/_grant-start-interaction.mdx'
import Finish from '/src/content/docs/partials/_grant-finish-interaction.mdx'
+import GetWalletAddress from '/src/content/docs/partials/code/guides/split-payments/_get-wallet-address.mdx'
+import GrantRequestIncomingPayments from '/src/content/docs/partials/code/guides/split-payments/_grant-request-incoming-payments.mdx'
+import CreateIncomingPayments from '/src/content/docs/partials/code/guides/split-payments/_create-incoming-payments.mdx'
+import GrantRequestQuote from '/src/content/docs/partials/code/guides/split-payments/_grant-request-quote.mdx'
+import CreateQuotes from '/src/content/docs/partials/code/guides/split-payments/_create-quotes.mdx'
+import GrantRequestOutgoingPayment from '/src/content/docs/partials/code/guides/split-payments/_grant-request-outgoing-payment.mdx'
+import CreateOutgoingPayments from '/src/content/docs/partials/code/guides/split-payments/_create-outgoing-payments.mdx'
+import RequestAGrantContinuation from '/src/content/docs/partials/code/guides/split-payments/_request-a-grant-continuation.mdx'
:::tip[Summary]
Learn how to take a single payment and split the value between multiple recipients.
@@ -61,94 +69,7 @@ Let's assume your wallet address is already saved to your platform, as is the me
Call the [Get Wallet Address API](/apis/wallet-address-server/operations/get-wallet-address) for each address.
-
-
-
-```ts
-const customerWalletAddress = await client.walletAddress.get({
- url: 'https://cloudninebank.example.com/customer'
-})
-const merchantWalletAddress = await client.walletAddress.get({
- url: 'https://happylifebank.example.com/merchant'
-})
-const platformWalletAddress = await client.walletAddress.get({
- url: 'https://coolwallet.example.com/platform'
-})
-```
-
-
-
-
-```rust wrap
-let customer_wallet_address = client.wallet_address().get("https://cloudninebank.example.com/customer").await?;
-let merchant_wallet_address = client.wallet_address().get("https://happylifebank.example.com/merchant").await?;
-let platform_wallet_address = client.wallet_address().get("https://coolwallet.example.com/platform").await?;
-```
-
-
-
-
-
-```php wrap
-$customerWalletAddress = $client->walletAddress()->get([
- 'url' => 'https://cloudninebank.example.com/customer'
-]);
-$merchantWalletAddress = $client->walletAddress()->get([
- 'url' => 'https://happylifebank.example.com/merchant'
-]);
-$platformWalletAddress = $client->walletAddress()->get([
- 'url' => 'https://coolwallet.example.com/platform'
-]);
-```
-
-
-
-
-
-```go wrap
-customerWalletAddress, err := client.WalletAddress.Get(context.TODO(), op.WalletAddressGetParams{
- URL: "https://cloudninebank.example.com/customer",
-})
-if err != nil {
- log.Fatalf("Error fetching customer wallet address: %v\n", err)
-}
-merchantWalletAddress, err := client.WalletAddress.Get(context.TODO(), op.WalletAddressGetParams{
- URL: "https://happylifebank.example.com/merchant",
-})
-if err != nil {
- log.Fatalf("Error fetching merchant wallet address: %v\n", err)
-}
-platformWalletAddress, err := client.WalletAddress.Get(context.TODO(), op.WalletAddressGetParams{
- URL: "https://coolwallet.example.com/platform",
-})
-if err != nil {
- log.Fatalf("Error fetching platform wallet address: %v\n", err)
-}
-```
-
-
-
-
-
-```java wrap
-var customerWalletAddress = client.walletAddress().get("https://cloudninebank.example.com/customer");
-var merchantWalletAddress = client.walletAddress().get("https://happylifebank.example.com/merchant");
-var platformWalletAddress = client.walletAddress().get("https://coolwallet.example.com/platform");
-```
-
-
-
-
-
-```csharp wrap
-var customerWalletAddress = await client.GetWalletAddressAsync("https://cloudninebank.example.com/customer");
-var merchantWalletAddress = await client.GetWalletAddressAsync("https://happylifebank.example.com/merchant");
-var platformWalletAddress = await client.GetWalletAddressAsync("https://happylifebank.example.com/platform");
-```
-
-
-
-
+
Example response
@@ -193,204 +114,7 @@ These calls obtain access tokens that allow your platform to request an incoming
If you and the merchant use the same account servicing entity, and as a result, the same authorization server, you only need one `incomingPayment` grant.
:::
-
-
-
-```ts wrap
-// Merchant
-const merchantIncomingPaymentGrant = await client.grant.request(
- {
- url: merchantWalletAddress.authServer
- },
- {
- access_token: {
- access: [
- {
- type: 'incoming-payment',
- actions: ['create']
- }
- ]
- }
- }
-)
-// Platform
-const platformIncomingPaymentGrant = await client.grant.request(
- {
- url: platformWalletAddress.authServer
- },
- {
- access_token: {
- access: [
- {
- type: 'incoming-payment',
- actions: ['create']
- }
- ]
- }
- }
-)
-```
-
-
-
-
-```rust wrap
-use open_payments::types::{AccessTokenRequest, AccessItem, IncomingPaymentAction, GrantRequest};
-let incoming_access = AccessTokenRequest {
- access: vec![AccessItem::IncomingPayment { actions: vec![IncomingPaymentAction::Create], identifier: None }],
-};
-let merchant_grant_request = GrantRequest::new(incoming_access.clone(), None);
-let platform_grant_request = GrantRequest::new(incoming_access, None);
-let merchant_incoming_payment_grant = client
- .grant()
- .request(&merchant_wallet_address.auth_server, &merchant_grant_request)
- .await?;
-let platform_incoming_payment_grant = client
- .grant()
- .request(&platform_wallet_address.auth_server, &platform_grant_request)
- .await?;
-```
-
-
-
-
-```php wrap
-// Merchant
-$merchantIncomingPaymentGrant = $client->grant()->request(
- [
- 'url' => $merchantWalletAddress->authServer
- ],
- [
- 'access_token' => [
- 'access' => [
- [
- 'type' => 'incoming-payment',
- 'actions' => ['create']
- ]
- ]
- ]
- ]
-);
-// Platform
-$platformIncomingPaymentGrant = $client->grant()->request(
- [
- 'url' => $platformWalletAddress->authServer
- ],
- [
- 'access_token' => [
- 'access' => [
- [
- 'type' => 'incoming-payment',
- 'actions' => ['create']
- ]
- ]
- ]
- ]
-);
-```
-
-
-
-
-
-```go wrap
-incomingAccess := as.AccessIncoming{
- Type: as.IncomingPayment,
- Actions: []as.AccessIncomingActions{as.AccessIncomingActionsCreate},
-}
-accessItem := as.AccessItem{}
-if err := accessItem.FromAccessIncoming(incomingAccess); err != nil {
- log.Fatalf("Error creating AccessItem: %v\n", err)
-}
-accessToken := struct {
- Access as.Access `json:"access"`
-}{
- Access: []as.AccessItem{accessItem},
-}
-// Merchant
-merchantIncomingPaymentGrant, err := client.Grant.Request(context.TODO(), op.GrantRequestParams{
- URL: *merchantWalletAddress.AuthServer,
- RequestBody: as.GrantRequestWithAccessToken{AccessToken: accessToken},
-})
-if err != nil {
- log.Fatalf("Error requesting merchant incoming payment grant: %v\n", err)
-}
-// Platform
-platformIncomingPaymentGrant, err := client.Grant.Request(context.TODO(), op.GrantRequestParams{
- URL: *platformWalletAddress.AuthServer,
- RequestBody: as.GrantRequestWithAccessToken{AccessToken: accessToken},
-})
-if err != nil {
- log.Fatalf("Error requesting platform incoming payment grant: %v\n", err)
-}
-```
-
-
-
-
-
-```java wrap
-// Merchant
-var merchantIncomingPaymentGrant = client.auth().grant().incomingPayment(
- merchantWalletAddress
-);
-
-// Platform
-var platformIncomingPaymentGrant = client.auth().grant().incomingPayment(
- platformWalletAddress
-);
-```
-
-
-
-
-
-```csharp wrap
-// Merchant
-var merchantIncomingPaymentGrant = await client.RequestGrantAsync(
- new RequestArgs
- {
- Url = merchantWalletAddress.AuthServer,
- },
- new GrantCreateBody
- {
- AccessToken = new AccessToken
- {
- Access =
- [
- new IncomingAccess
- {
- Actions = [Actions.Create]
- }
- ]
- }
- }
-);
-// Platform
-var platformIncomingPaymentGrant = await client.RequestGrantAsync(
- new RequestArgs
- {
- Url = platformWalletAddress.AuthServer,
- },
- new GrantCreateBody
- {
- AccessToken = new AccessToken
- {
- Access =
- [
- new IncomingAccess
- {
- Actions = [Actions.Create]
- }
- ]
- }
- }
-);
-```
-
-
-
-
+
Example response
@@ -428,202 +152,7 @@ This call requests an incoming payment resource be created on the merchant's wal
Remember that the merchant is receiving 99% of the payment (\$99.00 or `9900`) while you are keeping 1% as a fee (\$1.00 or `100`).
-
-
-
-```ts wrap
-// Merchant
-const merchantIncomingPayment = await client.incomingPayment.create(
- {
- url: merchantWalletAddress.resourceServer,
- accessToken: merchantIncomingPaymentGrant.access_token.value
- },
- {
- walletAddress: merchantWalletAddress.id,
- incomingAmount: {
- value: '9900',
- assetCode: 'USD',
- assetScale: 2
- }
- }
-)
-// Platform
-const platformIncomingPayment = await client.incomingPayment.create(
- {
- url: platformWalletAddress.resourceServer,
- accessToken: platformIncomingPaymentGrant.access_token.value
- },
- {
- walletAddress: platformWalletAddress.id,
- incomingAmount: {
- value: '100',
- assetCode: 'USD',
- assetScale: 2
- }
- }
-)
-```
-
-
-
-
-
-```rust wrap
-use open_payments::types::{IncomingPaymentRequest, Amount};
-let merchant_request = IncomingPaymentRequest {
- wallet_address: merchant_wallet_address.id.clone(),
- incoming_amount: Some(Amount { value: "9900".into(), asset_code: "USD".into(), asset_scale: 2 }),
- expires_at: None,
- metadata: None,
-};
-let platform_request = IncomingPaymentRequest {
- wallet_address: platform_wallet_address.id.clone(),
- incoming_amount: Some(Amount { value: "100".into(), asset_code: "USD".into(), asset_scale: 2 }),
- expires_at: None,
- metadata: None,
-};
-let merchant_incoming_payment = client
- .incoming_payments()
- .create(&merchant_wallet_address.resource_server, &merchant_request, Some(&merchant_incoming_payment_grant.access_token.value))
- .await?;
-let platform_incoming_payment = client
- .incoming_payments()
- .create(&platform_wallet_address.resource_server, &platform_request, Some(&platform_incoming_payment_grant.access_token.value))
- .await?;
-```
-
-
-
-
-
-```php wrap
-// Merchant
-$merchantIncomingPayment = $client->incomingPayment()->create(
- [
- 'url' => $merchantWalletAddress->resourceServer,
- 'accessToken' => $merchantIncomingPaymentGrant->access_token->value
- ],
- [
- 'walletAddress' => $merchantWalletAddress->id,
- 'incomingAmount' => [
- 'value' => '9900',
- 'assetCode' => 'USD',
- 'assetScale' => 2
- ]
- ]
-);
-// Platform
-$platformIncomingPayment = $client->incomingPayment()->create(
- [
- 'url' => $platformWalletAddress->resourceServer,
- 'accessToken' => $platformIncomingPaymentGrant->access_token->value
- ],
- [
- 'walletAddress' => $platformWalletAddress->id,
- 'incomingAmount' => [
- 'value' => '100',
- 'assetCode' => 'USD',
- 'assetScale' => 2
- ]
- ]
-);
-```
-
-
-
-
-
-```go wrap
-// Merchant
-merchantIncomingPayment, err := client.IncomingPayment.Create(context.TODO(), op.IncomingPaymentCreateParams{
- BaseURL: *merchantWalletAddress.ResourceServer,
- AccessToken: merchantIncomingPaymentGrant.AccessToken.Value,
- Payload: rs.CreateIncomingPaymentJSONBody{
- WalletAddressSchema: *merchantWalletAddress.Id,
- IncomingAmount: &rs.Amount{
- Value: "9900",
- AssetCode: "USD",
- AssetScale: 2,
- },
- },
-})
-if err != nil {
- log.Fatalf("Error creating merchant incoming payment: %v\n", err)
-}
-// Platform
-platformIncomingPayment, err := client.IncomingPayment.Create(context.TODO(), op.IncomingPaymentCreateParams{
- BaseURL: *platformWalletAddress.ResourceServer,
- AccessToken: platformIncomingPaymentGrant.AccessToken.Value,
- Payload: rs.CreateIncomingPaymentJSONBody{
- WalletAddressSchema: *platformWalletAddress.Id,
- IncomingAmount: &rs.Amount{
- Value: "100",
- AssetCode: "USD",
- AssetScale: 2,
- },
- },
-})
-if err != nil {
- log.Fatalf("Error creating platform incoming payment: %v\n", err)
-}
-```
-
-
-
-
-
-```java wrap
-// Merchant receives 99.00 USD (value 9900, scale 2)
-var merchantIncomingPayment = client.payment().createIncoming(
- merchantWalletAddress,
- merchantIncomingPaymentGrant,
- BigDecimal.valueOf(99.00)
-);
-
-// Platform receives 1.00 USD (value 100, scale 2)
-var platformIncomingPayment = client.payment().createIncoming(
- platformWalletAddress,
- platformIncomingPaymentGrant,
- BigDecimal.valueOf(1.00)
-);
-```
-
-
-
-
-
-```csharp wrap
-// Merchant
-var merchantIncomingPayment = await client.CreateIncomingPaymentAsync(
- new AuthRequestArgs
- {
- Url = merchantWalletAddress.ResourceServer,
- AccessToken = merchantIncomingPaymentGrant.AccessToken.Value
- },
- new IncomingPaymentBody
- {
- WalletAddress = merchantWalletAddress.Id,
- IncomingAmount = new Amount("9900", "USD", 2)
- }
-);
-// Platform
-var platformIncomingPayment = await client.CreateIncomingPaymentAsync(
- new AuthRequestArgs
- {
- Url = platformWalletAddress.ResourceServer,
- AccessToken = platformIncomingPaymentGrant.AccessToken.Value
- },
- new IncomingPaymentBody
- {
- WalletAddress = platformWalletAddress.Id,
- IncomingAmount = new Amount("100", "USD", 2)
- }
-);
-```
-
-
-
-
+
Example response
@@ -664,131 +193,7 @@ Use the customer's `authServer` details, received in Step 1, to call the
-
-
- ```ts wrap
- const customerQuoteGrant = await client.grant.request(
- {
- url: customerWalletAddress.authServer
- },
- {
- access_token: {
- access: [
- {
- type: 'quote',
- actions: ['create']
- }
- ]
- }
- }
- )
- ```
-
-
-
-
-
- ```rust wrap
- use open_payments::types::{AccessTokenRequest, AccessItem, QuoteAction, GrantRequest};
- let quote_access = AccessTokenRequest {
- access: vec![AccessItem::Quote { actions: vec![QuoteAction::Create] }],
- };
- let customer_grant_request = GrantRequest::new(quote_access, None);
- let customer_quote_grant = client
- .grant()
- .request(&customer_wallet_address.auth_server, &customer_grant_request)
- .await?;
- ```
-
-
-
-
-
-```php wrap
- $customerQuoteGrant = $client->grant()->request(
- [
- 'url' => $customerWalletAddress->authServer
- ],
- [
- 'access_token' => [
- 'access' => [
- [
- 'type' => 'quote',
- 'actions' => ['create']
- ]
- ]
- ]
- ]
- );
-```
-
-
-
-
-
-```go wrap
-quoteAccess := as.AccessQuote{
- Type: as.Quote,
- Actions: []as.AccessQuoteActions{as.Create},
-}
-quoteAccessItem := as.AccessItem{}
-if err := quoteAccessItem.FromAccessQuote(quoteAccess); err != nil {
- log.Fatalf("Error creating AccessItem: %v\n", err)
-}
-quoteAccessToken := struct {
- Access as.Access `json:"access"`
-}{
- Access: []as.AccessItem{quoteAccessItem},
-}
-customerQuoteGrant, err := client.Grant.Request(context.TODO(), op.GrantRequestParams{
- URL: *customerWalletAddress.AuthServer,
- RequestBody: as.GrantRequestWithAccessToken{AccessToken: quoteAccessToken},
-})
-if err != nil {
- log.Fatalf("Error requesting quote grant: %v\n", err)
-}
-```
-
-
-
-
-
-```java wrap
-var customerQuoteGrant = client.auth().grant().quote(
- customerWalletAddress
-);
-```
-
-
-
-
-
-```csharp wrap
-var customerQuoteGrant = await client.RequestGrantAsync(
- new RequestArgs
- {
- Url = customerWalletAddress.AuthServer,
- },
- new GrantCreateBody
- {
- AccessToken = new AccessToken
- {
- Access =
- [
- new QuoteAccess
- {
- Actions = [Actions.Create]
- }
- ]
- }
- }
-);
-```
-
-
-
-
+
Example response
@@ -826,196 +231,7 @@ First, let's request a quote resource associated with the merchant. The request
Next, call the Create Quote API again and request a quote resource associated with the platform's incoming payment `id`.
-
-
-
-```ts wrap
-// Merchant
-const merchantQuote = await client.quote.create(
- {
- url: customerWalletAddress.resourceServer,
- accessToken: customerQuoteGrant.access_token.value
- },
- {
- method: 'ilp',
- walletAddress: customerWalletAddress.id,
- receiver: merchantIncomingPayment.id
- }
-)
-// Platform
-const platformQuote = await client.quote.create(
- {
- url: customerWalletAddress.resourceServer,
- accessToken: customerQuoteGrant.access_token.value
- },
- {
- method: 'ilp',
- walletAddress: customerWalletAddress.id,
- receiver: platformIncomingPayment.id
- }
-)
-```
-
-
-
-
-```rust wrap
-use open_payments::types::{QuoteRequest, QuoteMethod};
-let merchant_quote_request = QuoteRequest {
- method: QuoteMethod::Ilp,
- wallet_address: Some(customer_wallet_address.id.clone()),
- receiver: Some(merchant_incoming_payment.id.clone()),
- debit_amount: None,
- receive_amount: None,
-};
-let platform_quote_request = QuoteRequest {
- method: QuoteMethod::Ilp,
- wallet_address: Some(customer_wallet_address.id.clone()),
- receiver: Some(platform_incoming_payment.id.clone()),
- debit_amount: None,
- receive_amount: None,
-};
-let merchant_quote = client
- .quotes()
- .create(&customer_wallet_address.resource_server, &merchant_quote_request, Some(&customer_quote_grant.access_token.value))
- .await?;
-let platform_quote = client
- .quotes()
- .create(&customer_wallet_address.resource_server, &platform_quote_request, Some(&customer_quote_grant.access_token.value))
- .await?;
-```
-
-
-
-
-
-```php wrap
-// Merchant
-$merchantQuote = $client->quote()->create(
- [
- 'url' => $customerWalletAddress->resourceServer,
- 'accessToken' => $customerQuoteGrant->access_token->value
- ],
- [
- 'method' => 'ilp',
- 'walletAddress' => $customerWalletAddress->id,
- 'receiver' => $merchantIncomingPayment->id
- ]
-);
-// Platform
-$platformQuote = $client->quote()->create(
- [
- 'url' => $customerWalletAddress->resourceServer,
- 'accessToken' => $customerQuoteGrant->access_token->value
- ],
- [
- 'method' => 'ilp',
- 'walletAddress' => $customerWalletAddress->id,
- 'receiver' => $platformIncomingPayment->id
- ]
-);
-```
-
-
-
-
-
-```go wrap
-// Merchant
-merchantQuote, err := client.Quote.Create(context.TODO(), op.QuoteCreateParams{
- BaseURL: *customerWalletAddress.ResourceServer,
- AccessToken: customerQuoteGrant.AccessToken.Value,
- Payload: rs.CreateQuoteJSONBody0{
- WalletAddressSchema: *customerWalletAddress.Id,
- Receiver: *merchantIncomingPayment.Id,
- Method: "ilp",
- },
-})
-if err != nil {
- log.Fatalf("Error creating merchant quote: %v\n", err)
-}
-// Platform
-platformQuote, err := client.Quote.Create(context.TODO(), op.QuoteCreateParams{
- BaseURL: *customerWalletAddress.ResourceServer,
- AccessToken: customerQuoteGrant.AccessToken.Value,
- Payload: rs.CreateQuoteJSONBody0{
- WalletAddressSchema: *customerWalletAddress.Id,
- Receiver: *platformIncomingPayment.Id,
- Method: "ilp",
- },
-})
-if err != nil {
- log.Fatalf("Error creating platform quote: %v\n", err)
-}
-```
-
-
-
-
-
-```java wrap
-// Merchant quote
-var merchantQuote = client.quote().create(
- customerQuoteGrant.getAccess().getToken(),
- customerWalletAddress,
- merchantIncomingPayment,
- Optional.empty(),
- Optional.empty()
-);
-
-// Platform quote
-var platformQuote = client.quote().create(
- customerQuoteGrant.getAccess().getToken(),
- customerWalletAddress,
- platformIncomingPayment,
- Optional.empty(),
- Optional.empty()
-);
-```
-
-
-
-
-
-```csharp wrap
-// Merchant
-var merchantQuote = await client.CreateQuoteAsync(
- new AuthRequestArgs
- {
- Url = customerWalletAddress.ResourceServer,
- AccessToken = customerQuoteGrant.AccessToken.Value
- },
- new QuoteBody
- {
- Method = PaymentMethod.Ilp,
- WalletAddress = customerWalletAddress.Id,
- Receiver = merchantIncomingPayment.Id,
- }
-);
-// Platform
-var platformQuote = await client.CreateQuoteAsync(
- new AuthRequestArgs
- {
- Url = customerWalletAddress.ResourceServer,
- AccessToken = customerQuoteGrant.AccessToken.Value
- },
- new QuoteBody
- {
- Method = PaymentMethod.Ilp,
- WalletAddress = customerWalletAddress.Id,
- Receiver = platformIncomingPayment.Id,
- }
-);
-```
-
-
-
-
-
-Each response returns a `receiveAmount`, a `debitAmount`, and other required information.
-
-- `debitAmount` - The amount the customer must pay toward the incoming payment resource (`receiveAmount` plus any applicable fees)
-- `receiveAmount` - The `incomingAmount` value from the incoming payment resource
+
Example response
@@ -1044,6 +260,11 @@ The following shows an example response from the merchant's wallet provider. A s
+Each response returns a `receiveAmount`, a `debitAmount`, and other required information.
+
+- `debitAmount` - The amount the customer must pay toward the incoming payment resource (`receiveAmount` plus any applicable fees)
+- `receiveAmount` - The `incomingAmount` value from the incoming payment resource
+
### 6. Request an interactive outgoing payment grant
Use the customer's `authServer` information received in Step 1 to call the [Grant Request API](/apis/auth-server/operations/post-request).
@@ -1052,258 +273,6 @@ This call obtains an access token that allows your platform to request outgoing
-
-
-
-```ts wrap
-combinedQuoteAmount = '10000' // 9900 + 100
-
-const pendingCustomerOutgoingPaymentGrant = await client.grant.request(
- {
- url: customerWalletAddress.authServer
- },
- {
- access_token: {
- access: [
- {
- identifier: customerWalletAddress.id,
- type: 'outgoing-payment',
- actions: ['create'],
- limits: {
- debitAmount: {
- assetCode: 'USD',
- assetScale: 2,
- value: combinedQuoteAmount
- }
- }
- }
- ]
- },
- interact: {
- start: ['redirect'],
- finish: {
- method: 'redirect',
- uri: 'https://paymentplatform.example/finish/{...}', // where to redirect the customer after they've completed interaction
- nonce: NONCE
- }
- }
- }
-)
-```
-
-
-
-
-```rust wrap
-use open_payments::types::{AccessTokenRequest, AccessItem, OutgoingPaymentAction, InteractRequest, InteractStart, InteractFinish, InteractFinishMethod, AccessLimits, Amount, GrantRequest};
-
-let merchant_amount = match merchant_quote.debit_amount.as_ref() {
- Some(a) => &a.value,
- None => {
- eprintln!("Missing debit_amount on merchant quote");
- return Ok(());
- }
-};
-let platform_amount = match platform_quote.debit_amount.as_ref() {
- Some(a) => &a.value,
- None => {
- eprintln!("Missing debit_amount on platform quote");
- return Ok(());
- }
-};
-let merchant_value = match merchant_amount.parse::() {
- Ok(v) => v,
- Err(_) => {
- eprintln!("Invalid merchant debit_amount value");
- return Ok(());
- }
-};
-let platform_value = match platform_amount.parse::() {
- Ok(v) => v,
- Err(_) => {
- eprintln!("Invalid platform debit_amount value");
- return Ok(());
- }
-};
-let combined_quote_amount = merchant_value + platform_value;
-let outgoing_access = AccessTokenRequest {
- access: vec![AccessItem::OutgoingPayment {
- identifier: Some(customer_wallet_address.id.clone()),
- actions: vec![OutgoingPaymentAction::Create],
- limits: Some(AccessLimits { debit_amount: Some(Amount { value: combined_quote_amount.to_string(), asset_code: "USD".into(), asset_scale: 2 }), ..Default::default() }),
- }],
-};
-let interact = InteractRequest { start: Some(vec![InteractStart::Redirect]), finish: Some(InteractFinish { method: InteractFinishMethod::Redirect, uri: Some("https://paymentplatform.example/finish/{...}".into()), nonce: Some("NONCE".into()) }) };
-let outgoing_grant_request = GrantRequest::new(outgoing_access, Some(interact));
-let pending_customer_outgoing_payment_grant = client
- .grant()
- .request(&customer_wallet_address.auth_server, &outgoing_grant_request)
- .await?;
-```
-
-
-
-
-
-```php wrap
-$combinedQuoteAmount = bcadd($merchantQuote->debitAmount->value, $platformQuote->debitAmount->value);
-
-$pendingCustomerOutgoingPaymentGrant = $client->grant()->request(
- [
- 'url' => $customerWalletAddress->authServer
- ],
- [
- 'access_token' => [
- 'access' => [
- [
- 'identifier' => $customerWalletAddress->id,
- 'type' => 'outgoing-payment',
- 'actions' => ['create'],
- 'limits' => [
- 'debitAmount' => [
- 'assetCode' => 'USD',
- 'assetScale' => 2,
- 'value' => $combinedQuoteAmount
- ]
- ]
- ]
- ]
- ],
- 'interact' => [
- 'start' => ['redirect'],
- 'finish' => [
- 'method' => 'redirect',
- 'uri' => 'https://paymentplatform.example/finish/{...}', // where to redirect the customer after they've completed interaction
- 'nonce' => 'NONCE'
- ]
- ]
- ]
-);
-```
-
-
-
-
-
-```go wrap
-combinedQuoteAmount := "10000" // merchantQuote.DebitAmount.Value + platformQuote.DebitAmount.Value
-limits := as.LimitsOutgoing{}
-if err := limits.FromLimitsOutgoing1(as.LimitsOutgoing1{
- DebitAmount: as.Amount{
- Value: combinedQuoteAmount,
- AssetCode: "USD",
- AssetScale: 2,
- },
-}); err != nil {
- log.Fatalf("Error creating limits: %v\n", err)
-}
-outgoingAccess := as.AccessOutgoing{
- Type: as.OutgoingPayment,
- Actions: []as.AccessOutgoingActions{as.AccessOutgoingActionsCreate},
- Identifier: *customerWalletAddress.Id,
- Limits: &limits,
-}
-outgoingAccessItem := as.AccessItem{}
-if err := outgoingAccessItem.FromAccessOutgoing(outgoingAccess); err != nil {
- log.Fatalf("Error creating AccessItem: %v\n", err)
-}
-outgoingAccessToken := struct {
- Access as.Access `json:"access"`
-}{
- Access: []as.AccessItem{outgoingAccessItem},
-}
-interact := &as.InteractRequest{
- Start: []as.InteractRequestStart{as.InteractRequestStartRedirect},
- Finish: &as.InteractRequestFinish{
- Method: as.Redirect,
- Uri: "https://paymentplatform.example/finish/{...}", // where to redirect the customer after they've completed interaction
- Nonce: NONCE,
- },
-}
-pendingCustomerOutgoingPaymentGrant, err := client.Grant.Request(context.TODO(), op.GrantRequestParams{
- URL: *customerWalletAddress.AuthServer,
- RequestBody: as.GrantRequestWithAccessToken{
- AccessToken: outgoingAccessToken,
- Interact: interact,
- },
-})
-if err != nil {
- log.Fatalf("Error requesting outgoing payment grant: %v\n", err)
-}
-```
-
-
-
-
-```java wrap
-var merchantDebit = new BigDecimal(merchantQuote.getDebitAmount().getValue());
-var platformDebit = new BigDecimal(platformQuote.getDebitAmount().getValue());
-var combinedQuoteAmount = merchantDebit.add(platformDebit);
-
-var debitAmount = Amount.build(
- combinedQuoteAmount,
- merchantQuote.getDebitAmount().getAssetCode(),
- merchantQuote.getDebitAmount().getAssetScale()
-);
-
-var urlToOpen = "https://paymentplatform.example/finish/{...}";
-
-var opContinueInteract = client.auth().grant().continuation(
- customerWalletAddress,
- debitAmount,
- URI.create(urlToOpen),
- "NONCE"
-);
-```
-
-
-
-
-
-```csharp wrap
-var combinedQuoteAmount = "10000"; // 9900 + 100
-
-var pendingCustomerOutgoingPaymentGrant = await client.RequestGrantAsync(
- new RequestArgs
- {
- Url = customerWalletAddress.AuthServer,
- },
- new GrantCreateBodyWithInteract
- {
- AccessToken = new AccessToken
- {
- Access =
- [
- new OutgoingAccess
- {
- Identifier = customerWalletAddress.Id,
- Actions = [Actions.Create],
- Limits = new OutgoingAccessLimits
- {
- DebitAmount = new AuthAmount(combinedQuoteAmount, "USD", 2),
- }
- }
- ]
- },
- Interact = new InteractRequest
- {
- Start = [Start.Redirect],
- Finish = new Finish
- {
- Method = FinishMethod.Redirect,
- Uri = new Uri(
- "https://localhost"), // where to redirect your user after they've completed the interaction
- Nonce = NONCE
- }
- }
- }
-);
-```
-
-
-
-
-
Example response
@@ -1325,6 +294,7 @@ var pendingCustomerOutgoingPaymentGrant = await client.RequestGrantAsync(
+
### 7. Start interaction with the customer
@@ -1347,97 +317,7 @@ Issue the request to the `continue.uri` provided in the initial outgoing payment
Include the `interact_ref` returned in the redirect URI's query parameters.
-
-
-
- ```ts wrap
- const customerOutgoingPaymentGrant = await client.grant.continue(
- {
- url: pendingCustomerOutgoingPaymentGrant.continue.uri,
- accessToken: pendingCustomerOutgoingPaymentGrant.continue.access_token.value
- },
- {
- interact_ref: interactRef
- }
- )
- ```
-
-
-
-
-```rust wrap
-let customer_outgoing_payment_grant = client
- .grant()
- .continue_grant(
- if let Some(continue_field) = &pending_customer_outgoing_payment_grant.continue_field { &continue_field.uri } else { eprintln!("Missing continue field on pending grant"); return Ok(()); },
- &interact_ref,
- if let Some(continue_field) = &pending_customer_outgoing_payment_grant.continue_field { Some(&continue_field.access_token.value) } else { None },
- )
- .await?;
-```
-
-
-
-
-
-```php wrap
-$customerOutgoingPaymentGrant = $client->grant()->continue(
- [
- 'url' => $pendingCustomerOutgoingPaymentGrant->continue->uri,
- 'accessToken' => $pendingCustomerOutgoingPaymentGrant->continue->access_token->value
- ],
- [
- 'interact_ref' => $interactRef
- ]
-);
-```
-
-
-
-
-
-```go wrap
-customerOutgoingPaymentGrant, err := client.Grant.Continue(context.TODO(), op.GrantContinueParams{
- URL: pendingCustomerOutgoingPaymentGrant.Continue.Uri,
- AccessToken: pendingCustomerOutgoingPaymentGrant.Continue.AccessToken.Value,
- InteractRef: INTERACT_REF
-})
-if err != nil {
- log.Fatalf("Error continuing grant: %v\n", err)
-}
-```
-
-
-
-
-```java wrap
-var customerOutgoingPaymentGrant = client.auth().grant().finalize(
- opContinueInteract,
- interactRef
-);
-```
-
-
-
-
-
-```csharp wrap
-var customerOutgoingPaymentGrant = await client.ContinueGrantAsync(
- new AuthRequestArgs
- {
- Url = pendingCustomerOutgoingPaymentGrant.Continue.Uri,
- AccessToken = pendingCustomerOutgoingPaymentGrant.Continue.AccessToken.Value
- },
- new GrantContinueBody
- {
- InteractRef = interactRef
- }
-);
-```
-
-
-
-
+
Example response
@@ -1477,187 +357,7 @@ Because the quotes contain debit and receive amounts, we won't specify any other
Use the access token returned in Step 5 that's associated with the merchant to call the [Create Outgoing Payment API](/apis/resource-server/operations/create-outgoing-payment). Include the appropriate `quoteId` in the request. Now, do the same with the access token associated with your platform.
-
-
-
-```ts wrap
-// Merchant
-const customerOutgoingPaymentToMerchant = await client.outgoingPayment.create(
- {
- url: customerWalletAddress.resourceServer,
- accessToken: customerOutgoingPaymentGrant.access_token.value
- },
- {
- walletAddress: customerWalletAddress.id,
- quoteId: merchantQuote.id
- }
-)
-// Platform
-const customerOutgoingPaymentToPlatform = await client.outgoingPayment.create(
- {
- url: customerWalletAddress.resourceServer,
- accessToken: customerOutgoingPaymentGrant.access_token.value
- },
- {
- walletAddress: customerWalletAddress.id,
- quoteId: platformQuote.id
- }
-)
-```
-
-
-
-
-```rust wrap
-use open_payments::types::OutgoingPaymentRequest;
-let merchant_outgoing_request = OutgoingPaymentRequest {
- wallet_address: customer_wallet_address.id.clone(),
- receiver: Some(merchant_incoming_payment.id.clone()),
- debit_amount: None,
- receive_amount: None,
- quote_id: Some(merchant_quote.id.clone()),
-};
-let platform_outgoing_request = OutgoingPaymentRequest {
- wallet_address: customer_wallet_address.id.clone(),
- receiver: Some(platform_incoming_payment.id.clone()),
- debit_amount: None,
- receive_amount: None,
- quote_id: Some(platform_quote.id.clone()),
-};
-let customer_outgoing_payment_to_merchant = client
- .outgoing_payments()
- .create(&customer_wallet_address.resource_server, &merchant_outgoing_request, Some(&customer_outgoing_payment_grant.access_token.value))
- .await?;
-let customer_outgoing_payment_to_platform = client
- .outgoing_payments()
- .create(&customer_wallet_address.resource_server, &platform_outgoing_request, Some(&customer_outgoing_payment_grant.access_token.value))
- .await?;
-```
-
-
-
-
-
-```php wrap
-// Merchant
-$customerOutgoingPaymentToMerchant = $client->outgoingPayment()->create(
- [
- 'url' => $customerWalletAddress->resourceServer,
- 'accessToken' => $customerOutgoingPaymentGrant->access_token->value
- ],
- [
- 'walletAddress' => $customerWalletAddress->id,
- 'quoteId' => $merchantQuote->id
- ]
-);
-// Platform
-$customerOutgoingPaymentToPlatform = $client->outgoingPayment()->create(
- [
- 'url' => $customerWalletAddress->resourceServer,
- 'accessToken' => $customerOutgoingPaymentGrant->access_token->value
- ],
- [
- 'walletAddress' => $customerWalletAddress->id,
- 'quoteId' => $platformQuote->id
- ]
-);
-```
-
-
-
-
-
-```go wrap
-// Merchant
-var merchantOutgoingPayload rs.CreateOutgoingPaymentRequest
-if err := merchantOutgoingPayload.FromCreateOutgoingPaymentWithQuote(rs.CreateOutgoingPaymentWithQuote{
- WalletAddressSchema: *customerWalletAddress.Id,
- QuoteId: *merchantQuote.Id,
-}); err != nil {
- log.Fatalf("Error creating merchant payload: %v\n", err)
-}
-customerOutgoingPaymentToMerchant, err := client.OutgoingPayment.Create(context.TODO(), op.OutgoingPaymentCreateParams{
- BaseURL: *customerWalletAddress.ResourceServer,
- AccessToken: customerOutgoingPaymentGrant.AccessToken.Value,
- Payload: merchantOutgoingPayload,
-})
-if err != nil {
- log.Fatalf("Error creating outgoing payment to merchant: %v\n", err)
-}
-// Platform
-var platformOutgoingPayload rs.CreateOutgoingPaymentRequest
-if err := platformOutgoingPayload.FromCreateOutgoingPaymentWithQuote(rs.CreateOutgoingPaymentWithQuote{
- WalletAddressSchema: *customerWalletAddress.Id,
- QuoteId: *platformQuote.Id,
-}); err != nil {
- log.Fatalf("Error creating platform payload: %v\n", err)
-}
-customerOutgoingPaymentToPlatform, err := client.OutgoingPayment.Create(context.TODO(), op.OutgoingPaymentCreateParams{
- BaseURL: *customerWalletAddress.ResourceServer,
- AccessToken: customerOutgoingPaymentGrant.AccessToken.Value,
- Payload: platformOutgoingPayload,
-})
-if err != nil {
- log.Fatalf("Error creating outgoing payment to platform: %v\n", err)
-}
-```
-
-
-
-
-
-```java wrap
-// Merchant
-var customerOutgoingPaymentToMerchant = client.payment().createOutgoing(
- customerOutgoingPaymentGrant,
- customerWalletAddress,
- merchantQuote
-);
-
-// Platform
-var customerOutgoingPaymentToPlatform = client.payment().createOutgoing(
- customerOutgoingPaymentGrant,
- customerWalletAddress,
- platformQuote
-);
-```
-
-
-
-
-
-```csharp wrap
-// Merchant
-var customerOutgoingPaymentToMerchant = await client.CreateOutgoingPaymentAsync(
- new AuthRequestArgs
- {
- Url = customerWalletAddress.ResourceServer,
- AccessToken = customerOutgoingPaymentGrant.AccessToken.Value
- },
- new OutgoingPaymentBodyFromQuote
- {
- WalletAddress = customerWalletAddress.Id,
- QuoteId = merchantQuote.Id,
- }
-);
-// Platform
-var customerOutgoingPaymentToPlatform = await client.CreateOutgoingPaymentAsync(
- new AuthRequestArgs
- {
- Url = customerWalletAddress.ResourceServer,
- AccessToken = customerOutgoingPaymentGrant.AccessToken.Value
- },
- new OutgoingPaymentBodyFromQuote
- {
- WalletAddress = customerWalletAddress.Id,
- QuoteId = platformQuote.Id,
- }
-);
-```
-
-
-
-
+
Example response
diff --git a/docs/src/content/docs/partials/code/guides/accept-otp-online-purchase/_create-incoming-payment.mdx b/docs/src/content/docs/partials/code/guides/accept-otp-online-purchase/_create-incoming-payment.mdx
new file mode 100644
index 00000000..b3df3366
--- /dev/null
+++ b/docs/src/content/docs/partials/code/guides/accept-otp-online-purchase/_create-incoming-payment.mdx
@@ -0,0 +1,121 @@
+import { Tabs, TabItem } from '@astrojs/starlight/components'
+
+
+
+
+```ts wrap
+const retailerIncomingPayment = await.client.incomingPayment.create(
+ {
+ url: retailerWalletAddress.resourceServer,
+ accessToken: retailerIncomingPaymentGrant.access_token.value
+ },
+ {
+ walletAddress: retailerWalletAddress.id,
+ incomingAmount: {
+ value: '140000',
+ assetCode: 'MXN',
+ assetScale: 2
+ }
+ }
+)
+```
+
+
+
+
+```rust wrap
+use open_payments::types::{IncomingPaymentRequest, Amount};
+
+let incoming_request = IncomingPaymentRequest {
+wallet_address: retailer_wallet_address.id.clone(),
+incoming_amount: Some(Amount { value: "140000".into(), asset_code: "MXN".into(), asset_scale: 2 }),
+expires_at: None,
+metadata: None,
+};
+
+let retailer_incoming_payment = client
+.incoming_payments()
+.create(
+&retailer_wallet_address.resource_server,
+&incoming_request,
+Some(&retailer_incoming_payment_grant.access_token.value),
+)
+.await?;
+
+```
+
+
+
+
+
+```php
+$retailerIncomingPayment = $client->incomingPayment()->create(
+ [
+ 'url' => $retailerWalletAddress->resourceServer,
+ 'accessToken' => $retailerIncomingPaymentGrant->access_token->value
+ ],
+ [
+ 'walletAddress' => $retailerWalletAddress->id,
+ 'incomingAmount' => [
+ 'value' => '140000',
+ 'assetCode' => 'MXN',
+ 'assetScale' => 2
+ ]
+ ]
+);
+```
+
+
+
+
+```go wrap
+incomingPayment, err := client.IncomingPayment.Create(context.TODO(), op.IncomingPaymentCreateParams{
+ BaseURL: *retailerWalletAddress.ResourceServer,
+ AccessToken: retailerIncomingPaymentGrant.AccessToken.Value,
+ Payload: rs.CreateIncomingPaymentJSONBody{
+ WalletAddressSchema: *retailerWalletAddress.Id,
+ IncomingAmount: &rs.Amount{
+ Value: "140000",
+ AssetCode: "MXN",
+ AssetScale: 2,
+ },
+ },
+})
+if err != nil {
+ log.Fatalf("Error creating incoming payment: %v\n", err)
+}
+```
+
+
+
+
+
+```java wrap
+var retailerIncomingPayment = client.payment().createIncoming(
+ retailerWalletAddress,
+ retailerIncomingPaymentGrant,
+ BigDecimal.valueOf(1400.00)
+);
+```
+
+
+
+
+
+```csharp wrap
+var retailerIncomingPayment = await client.CreateIncomingPaymentAsync(
+ new AuthRequestArgs
+ {
+ Url = retailerWalletAddress.ResourceServer,
+ AccessToken = retailerIncomingPaymentGrant.AccessToken.Value
+ },
+ new IncomingPaymentBody
+ {
+ WalletAddress = retailerWalletAddress.Id,
+ IncomingAmount = new Amount("140000", "MXN", 2)
+ }
+);
+```
+
+
+
diff --git a/docs/src/content/docs/partials/code/guides/accept-otp-online-purchase/_create-outgoing-payment.mdx b/docs/src/content/docs/partials/code/guides/accept-otp-online-purchase/_create-outgoing-payment.mdx
new file mode 100644
index 00000000..c085e6d9
--- /dev/null
+++ b/docs/src/content/docs/partials/code/guides/accept-otp-online-purchase/_create-outgoing-payment.mdx
@@ -0,0 +1,114 @@
+import { Tabs, TabItem } from '@astrojs/starlight/components'
+
+
+
+
+```ts wrap
+const customerOutgoingPayment = await client.outgoingPayment.create(
+ {
+ url: customerWalletAddress.resourceServer,
+ accessToken: customerOutgoingPaymentGrant.access_token.value
+ },
+ {
+ walletAddress: customerWalletAddress.id,
+ quoteId: customerQuote.id
+ }
+)
+```
+
+
+
+
+```rust wrap
+use open_payments::types::OutgoingPaymentRequest;
+let outgoing_request = OutgoingPaymentRequest {
+ wallet_address: customer_wallet_address.id.clone(),
+ receiver: Some(retailer_incoming_payment.id.clone()),
+ debit_amount: None,
+ receive_amount: None,
+ quote_id: Some(customer_quote.id.clone()),
+};
+let customer_outgoing_payment_to_retailer = client
+ .outgoing_payments()
+ .create(
+ &customer_wallet_address.resource_server,
+ &outgoing_request,
+ Some(&customer_outgoing_payment_grant.access_token.value),
+ )
+ .await?;
+```
+
+
+
+
+
+```php
+$customerOutgoingPayment = $client->outgoingPayment()->create(
+ [
+ 'url' => $customerWalletAddress->resourceServer,
+ 'accessToken' => $customerOutgoingPaymentGrant->access_token->value
+ ],
+ [
+ 'walletAddress' => $customerWalletAddress->id,
+ 'quoteId' => $customerQuote->id
+ ]
+);
+```
+
+
+
+
+
+```go
+var outgoingPayload rs.CreateOutgoingPaymentRequest
+if err := outgoingPayload.FromCreateOutgoingPaymentWithQuote(rs.CreateOutgoingPaymentWithQuote{
+ WalletAddressSchema: *customerWalletAddress.Id,
+ QuoteId: *customerQuote.Id,
+}); err != nil {
+ log.Fatalf("Error creating payload: %v\n", err)
+}
+
+customerOutgoingPayment, err := client.OutgoingPayment.Create(context.TODO(), op.OutgoingPaymentCreateParams{
+ BaseURL: customerWalletAddress.ResourceServer,
+ AccessToken: customerOutgoingPaymentGrant.AccessToken.Value,
+ Payload: outgoingPayload
+})
+if err != nil {
+ log.Fatalf("Error creating outgoing payment: %v\n", err)
+}
+```
+
+
+
+
+
+```java wrap
+var customerOutgoingPayment = client.payment().createOutgoing(
+ customerOutgoingPaymentGrant,
+ customerWalletAddress,
+ customerQuote
+);
+```
+
+
+
+
+
+```csharp wrap
+var customerOutgoingPayment = await client.CreateOutgoingPaymentAsync(
+ new AuthRequestArgs
+ {
+ Url = customerWalletAddress.ResourceServer,
+ AccessToken = customerOutgoingPaymentGrant.AccessToken.Value
+ },
+ new OutgoingPaymentBodyFromQuote
+ {
+ WalletAddress = customerWalletAddress.Id,
+ QuoteId = customerQuote.Id,
+ }
+);
+```
+
+
+
+
diff --git a/docs/src/content/docs/partials/code/guides/accept-otp-online-purchase/_create-quote.mdx b/docs/src/content/docs/partials/code/guides/accept-otp-online-purchase/_create-quote.mdx
new file mode 100644
index 00000000..b55143c6
--- /dev/null
+++ b/docs/src/content/docs/partials/code/guides/accept-otp-online-purchase/_create-quote.mdx
@@ -0,0 +1,117 @@
+import { Tabs, TabItem } from '@astrojs/starlight/components'
+
+
+
+
+```ts wrap
+const customerQuote = await client.quote.create(
+ {
+ url: customerWalletAddress.resourceServer,
+ accessToken: customerQuoteGrant.access_token.value
+ },
+ {
+ method: 'ilp',
+ walletAddress: customerWalletAddress.id,
+ receiver: retailerIncomingPayment.id
+ }
+)
+```
+
+
+
+
+```rust wrap
+use open_payments::types::{QuoteRequest, QuoteMethod};
+
+let quote_request = QuoteRequest {
+method: QuoteMethod::Ilp,
+wallet_address: Some(customer_wallet_address.id.clone()),
+receiver: Some(retailer_incoming_payment.id.clone()),
+debit_amount: None,
+receive_amount: None,
+};
+
+let customer_quote = client
+.quotes()
+.create(
+&customer_wallet_address.resource_server,
+"e_request,
+Some(&customer_quote_grant.access_token.value),
+)
+.await?;
+
+```
+
+
+
+
+```php
+$customerQuote = $client->quote()->create(
+ [
+ 'url' => $customerWalletAddress->resourceServer,
+ 'accessToken' => $customerQuoteGrant->access_token->value
+ ],
+ [
+ 'method' => 'ilp',
+ 'walletAddress' => $customerWalletAddress->id,
+ 'receiver' => $retailerIncomingPayment->id
+ ]
+);
+```
+
+
+
+
+
+```go wrap
+customerQuote, err := client.Quote.Create(context.TODO(), op.QuoteCreateParams{
+ BaseURL: *customerWalletAddress.ResourceServer,
+ AccessToken: customerQuoteGrant.AccessToken.Value,
+ Payload: rs.CreateQuoteJSONBody0{
+ WalletAddressSchema: *customerWalletAddress.Id,
+ Receiver: *incomingPayment.Id,
+ Method: "ilp",
+ },
+})
+if err != nil {
+ log.Fatalf("Error creating quote: %v\n", err)
+}
+```
+
+
+
+
+
+```java wrap
+var customerQuote = client.quote().create(
+ customerQuoteGrant.getAccess().getToken(),
+ customerWalletAddress,
+ retailerIncomingPayment,
+ Optional.empty(),
+ Optional.empty()
+);
+```
+
+
+
+
+
+```csharp wrap
+var customerQuote = await client.CreateQuoteAsync(
+ new AuthRequestArgs
+ {
+ Url = customerWalletAddress.ResourceServer,
+ AccessToken = customerQuoteGrant.AccessToken.Value
+ },
+ new QuoteBody
+ {
+ WalletAddress = customerWalletAddress.Id,
+ Receiver = retailerWalletAddress.Id,
+ Method = PaymentMethod.Ilp
+ }
+);
+```
+
+
+
+
diff --git a/docs/src/content/docs/partials/code/guides/accept-otp-online-purchase/_get-wallet-address.mdx b/docs/src/content/docs/partials/code/guides/accept-otp-online-purchase/_get-wallet-address.mdx
new file mode 100644
index 00000000..27000738
--- /dev/null
+++ b/docs/src/content/docs/partials/code/guides/accept-otp-online-purchase/_get-wallet-address.mdx
@@ -0,0 +1,75 @@
+import { Tabs, TabItem } from '@astrojs/starlight/components'
+
+
+
+
+```ts wrap
+const customerWalletAddress = await client.walletAddress.get({
+ url: 'https://cloudninebank.example.com/customer'
+})
+const retailerWalletAddress = await client.walletAddress.get({
+ url: 'https://happylifebank.example.com/retailer'
+})
+```
+
+
+
+
+```rust wrap
+let sender_wallet_address = client.wallet_address().get("https://cloudninebank.example.com/customer").await?;
+let retailer_wallet_address = client.wallet_address().get("https://happylifebank.example.com/retailer").await?;
+```
+
+
+
+```php
+$customerWalletAddress = $client->walletAddress()->get([
+ 'url' => 'https://cloudninebank.example.com/customer'
+]);
+$retailerWalletAddress = $client->walletAddress()->get([
+ 'url' => 'https://happylifebank.example.com/retailer'
+]);
+```
+
+
+
+
+
+```go wrap
+customerWalletAddress, err := client.WalletAddress.Get(context.TODO(), op.WalletAddressGetParams{
+ URL: "https://cloudninebank.example.com/customer",
+})
+if err != nil {
+ log.Fatalf("Error fetching customer wallet address: %v\n", err)
+}
+
+retailerWalletAddress, err := client.WalletAddress.Get(context.TODO(), op.WalletAddressGetParams{
+ URL: "https://happylifebank.example.com/retailer",
+})
+if err != nil {
+ log.Fatalf("Error fetching retailer wallet address: %v\n", err)
+}
+
+```
+
+
+
+
+
+```java wrap
+var customerWalletAddress = client.walletAddress().get("https://cloudninebank.example.com/customer");
+var retailerWalletAddress = client.walletAddress().get("https://happylifebank.example.com/retailer");
+```
+
+
+
+
+
+```csharp wrap
+var customerWalletAddress = await client.GetWalletAddressAsync("https://cloudninebank.example.com/customer");
+var retailerWalletAddress = await client.GetWalletAddressAsync("https://happylifebank.example.com/retailer");
+```
+
+
+
+
diff --git a/docs/src/content/docs/partials/code/guides/accept-otp-online-purchase/_grant-continuation-request.mdx b/docs/src/content/docs/partials/code/guides/accept-otp-online-purchase/_grant-continuation-request.mdx
new file mode 100644
index 00000000..5e163926
--- /dev/null
+++ b/docs/src/content/docs/partials/code/guides/accept-otp-online-purchase/_grant-continuation-request.mdx
@@ -0,0 +1,103 @@
+import { Tabs, TabItem } from '@astrojs/starlight/components'
+
+
+
+
+```ts wrap
+const customerOutgoingPaymentGrant = await client.grant.continue(
+ {
+ url: pendingCustomerOutgoingPaymentGrant.continue.uri,
+ accessToken: pendingCustomerOutgoingPaymentGrant.continue.access_token.value
+ },
+ {
+ interact_ref: interactRef
+ }
+)
+```
+
+
+
+
+```rust wrap
+let continue_field = match &pending_customer_outgoing_payment_grant.continue_field {
+ Some(c) => c,
+ None => {
+ eprintln!("Missing continue field on pending grant");
+ return Ok(());
+ }
+};
+
+let customer_outgoing_payment_grant = client
+.grant()
+.continue_grant(
+&continue_field.uri,
+&interact_ref,
+Some(&continue_field.access_token.value),
+)
+.await?;
+
+```
+
+
+
+
+
+```php
+$customerOutgoingPaymentGrant = $client->grant()->continue(
+ [
+ 'url' => $pendingCustomerOutgoingPaymentGrant->continue->uri,
+ 'accessToken' => $pendingCustomerOutgoingPaymentGrant->continue->access_token->value
+ ],
+ [
+ 'interact_ref' => $interactRef
+ ]
+);
+```
+
+
+
+
+
+```go wrap
+customerOutgoingPaymentGrant, err := client.Grant.Continue(context.TODO(), op.GrantContinueParams{
+ URL: pendingCustomerOutgoingPaymentGrant.Continue.Uri,
+ AccessToken: pendingCustomerOutgoingPaymentGrant.Continue.AccessToken.Value,
+ InteractRef: INTERACT_REF,
+})
+if err != nil {
+ log.Fatalf("Error continuing grant: %v\n", err)
+}
+```
+
+
+
+
+
+```java wrap
+var customerOutgoingPaymentGrant = client.auth().grant().finalize(
+ opContinueInteract,
+ interactRef
+);
+```
+
+
+
+
+
+```csharp wrap
+var customerOutgoingPaymentGrant = await client.ContinueGrantAsync(
+ new AuthRequestArgs
+ {
+ Url = pendingCustomerOutgoingPaymentGrant.Continue.Uri,
+ AccessToken = pendingCustomerOutgoingPaymentGrant.Continue.AccessToken.Value
+ },
+ new GrantContinueBody
+ {
+ InteractRef = interactRef
+ }
+);
+```
+
+
+
+
diff --git a/docs/src/content/docs/partials/code/guides/accept-otp-online-purchase/_grant-request-incoming-payment.mdx b/docs/src/content/docs/partials/code/guides/accept-otp-online-purchase/_grant-request-incoming-payment.mdx
new file mode 100644
index 00000000..c5da028d
--- /dev/null
+++ b/docs/src/content/docs/partials/code/guides/accept-otp-online-purchase/_grant-request-incoming-payment.mdx
@@ -0,0 +1,129 @@
+import { Tabs, TabItem } from '@astrojs/starlight/components'
+
+
+
+
+```ts wrap
+const retailerIncomingPaymentGrant = await client.grant.request(
+ {
+ url: retailerWalletAddress.authServer
+ },
+ {
+ access_token: {
+ access: [
+ {
+ type: 'incoming-payment',
+ actions: ['create']
+ }
+ ]
+ }
+ }
+)
+```
+
+
+
+
+```rust wrap
+use open_payments::types::{AccessTokenRequest, AccessItem, IncomingPaymentAction, GrantRequest};
+
+let incoming_access = AccessTokenRequest {
+access: vec![AccessItem::IncomingPayment { actions: vec![IncomingPaymentAction::Create], identifier: None }],
+};
+let incoming_grant_request = GrantRequest::new(incoming_access, None);
+
+let retailer_incoming_payment_grant = client
+.grant()
+.request(&retailer_wallet_address.auth_server, &incoming_grant_request)
+.await?;
+
+```
+
+
+
+
+
+```php
+$retailerIncomingPaymentGrant = $client->grant()->request(
+ [
+ 'url' => $retailerWalletAddress->authServer
+ ],
+ [
+ 'access_token' => [
+ 'access' => [
+ [
+ 'type' => 'incoming-payment',
+ 'actions' => ['create']
+ ]
+ ]
+ ]
+ ]
+);
+```
+
+
+
+
+
+```go wrap
+incomingAccess := as.AccessIncoming{
+ Type: as.IncomingPayment,
+ Actions: []as.AccessIncomingActions{as.AccessIncomingActionsCreate},
+}
+accessItem := as.AccessItem{}
+if err := accessItem.FromAccessIncoming(incomingAccess); err != nil {
+ log.Fatalf("Error creating AccessItem: %v\n", err)
+}
+accessToken := struct {
+ Access as.Access `json:"access"`
+}{
+ Access: []as.AccessItem{accessItem},
+}
+
+retailerIncomingPaymentGrant, err := client.Grant.Request(context.TODO(), op.GrantRequestParams{
+ URL: *retailerWalletAddress.AuthServer,
+ RequestBody: as.GrantRequestWithAccessToken{AccessToken: accessToken},
+})
+if err != nil {
+ log.Fatalf("Error requesting incoming payment grant: %v\n", err)
+}
+```
+
+
+
+
+
+```java wrap
+var retailerIncomingPaymentGrant = client.auth().grant().incomingPayment(
+ retailerWalletAddress
+);
+```
+
+
+
+
+
+```csharp wrap
+var retailerIncomingPaymentGrant = await client.RequestGrantAsync(
+ new RequestArgs
+ {
+ Url = retailerWalletAddress.AuthServer,
+ },
+ new GrantCreateBody
+ {
+ AccessToken = new AccessToken
+ {
+ Access =
+ [
+ new IncomingAccess
+ {
+ Actions = [Actions.Create]
+ }
+ ]
+ }
+ }
+);
+```
+
+
+
diff --git a/docs/src/content/docs/partials/code/guides/accept-otp-online-purchase/_grant-request-outgoing-payment.mdx b/docs/src/content/docs/partials/code/guides/accept-otp-online-purchase/_grant-request-outgoing-payment.mdx
new file mode 100644
index 00000000..49e6db86
--- /dev/null
+++ b/docs/src/content/docs/partials/code/guides/accept-otp-online-purchase/_grant-request-outgoing-payment.mdx
@@ -0,0 +1,216 @@
+import { Tabs, TabItem } from '@astrojs/starlight/components'
+
+
+
+
+```ts wrap
+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
+ }
+ }
+ }
+)
+```
+
+
+
+
+```rust wrap
+use open_payments::types::{AccessTokenRequest, AccessItem, OutgoingPaymentAction, InteractRequest, InteractStart, InteractFinish, InteractFinishMethod, AccessLimits, Amount, GrantRequest};
+
+let access_limits = AccessLimits {
+ debit_amount: Some(Amount { value: "140000".into(), asset_code: "MXN".into(), asset_scale: 2 }),
+ ..Default::default()
+};
+let access_request = AccessTokenRequest {
+ access: vec![AccessItem::OutgoingPayment {
+ identifier: Some(customer_wallet_address.id.clone()),
+ actions: vec![OutgoingPaymentAction::Create],
+ limits: Some(access_limits),
+ }],
+};
+let interact_request = InteractRequest {
+ start: Some(vec![InteractStart::Redirect]),
+ finish: Some(InteractFinish {
+ method: InteractFinishMethod::Redirect,
+ uri: Some("https://paymentplatform.example/finish/{...}".into()),
+ nonce: Some("NONCE".into()),
+ }),
+};
+
+let grant_request = GrantRequest::new(access_request, Some(interact_request));
+let pending_customer_outgoing_payment_grant = client
+ .grant()
+ .request(&customer_wallet_address.auth_server, &grant_request)
+ .await?;
+```
+
+
+
+
+```php
+$pendingCustomerOutgoingPaymentGrant = $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'
+ ]
+ ]
+ ]
+);
+```
+
+
+
+
+
+```go wrap
+outgoingAccess := as.AccessOutgoing{
+ Type: as.OutgoingPayment,
+ Actions: []as.AccessOutgoingActions{as.AccessOutgoingActionsCreate},
+ Identifier: *customerWalletAddress.Id,
+ Limits: &as.LimitsOutgoing{
+ DebitAmount: &as.Amount{
+ Value: "140000",
+ AssetCode: "MXN",
+ AssetScale: 2,
+ },
+ },
+}
+outgoingAccessItem := as.AccessItem{}
+if err := outgoingAccessItem.FromAccessOutgoing(outgoingAccess); err != nil {
+ log.Fatalf("Error creating AccessItem: %v\n", err)
+}
+outgoingAccessToken := struct {
+ Access as.Access `json:"access"`
+}{
+ Access: []as.AccessItem{outgoingAccessItem},
+}
+interact := &as.InteractRequest{
+ Start: []as.InteractRequestStart{as.InteractRequestStartRedirect},
+ Finish: &as.InteractRequestFinish{
+ Method: as.Redirect,
+ Uri: "https://paymentplatform.example/finish/{...}",
+ Nonce: NONCE,
+ },
+}
+
+pendingCustomerOutgoingPaymentGrant, err := client.Grant.Request(context.TODO(), op.GrantRequestParams{
+ URL: *customerWalletAddress.AuthServer,
+ RequestBody: as.GrantRequestWithAccessToken{
+ AccessToken: outgoingAccessToken,
+ Interact: interact,
+ },
+})
+
+if err != nil {
+ log.Fatalf("Error requesting outgoing payment grant: %v\n", err)
+}
+```
+
+
+
+
+
+```java wrap
+var urlToOpen = "https://paymentplatform.example/finish/{...}";
+
+var opContinueInteract = client.auth().grant().continuation(
+ customerWalletAddress,
+ customerQuote.getDebitAmount(),
+ URI.create(urlToOpen),
+ "NONCE"
+);
+```
+
+
+
+
+
+```csharp wrap
+var pendingCustomerOutgoingPaymentGrant = await client.RequestGrantAsync(
+ new RequestArgs
+ {
+ Url = customerWalletAddress.AuthServer,
+ },
+ new GrantCreateBodyWithInteract
+ {
+ AccessToken = new AccessToken
+ {
+ Access =
+ [
+ new OutgoingAccess
+ {
+ Identifier = customerWalletAddress.Id,
+ Actions = [Actions.Create],
+ Limits = new OutgoingAccessLimits
+ {
+ DebitAmount = new AuthAmount("140000", "MXN", 2)
+ }
+ }
+ ]
+ },
+ Interact = new InteractRequest
+ {
+ Start = [Start.Redirect],
+ Finish = new Finish
+ {
+ Method = FinishMethod.Redirect,
+ Uri = new Uri("https://localhost"),
+ Nonce = NONCE
+ }
+ }
+ }
+);
+```
+
+
+
+
diff --git a/docs/src/content/docs/partials/code/guides/accept-otp-online-purchase/_grant-request-quote.mdx b/docs/src/content/docs/partials/code/guides/accept-otp-online-purchase/_grant-request-quote.mdx
new file mode 100644
index 00000000..fdc295fa
--- /dev/null
+++ b/docs/src/content/docs/partials/code/guides/accept-otp-online-purchase/_grant-request-quote.mdx
@@ -0,0 +1,128 @@
+import { Tabs, TabItem } from '@astrojs/starlight/components'
+
+
+
+
+```ts wrap
+const customerQuoteGrant = await client.grant.request(
+ {
+ url: customerWalletAddress.authServer
+ },
+ {
+ access_token: {
+ access: [
+ {
+ type: 'quote',
+ actions: ['create']
+ }
+ ]
+ }
+ }
+)
+```
+
+
+
+
+```rust wrap
+use open_payments::types::{AccessTokenRequest, AccessItem, QuoteAction, GrantRequest};
+
+let quote_access = AccessTokenRequest {
+access: vec![AccessItem::Quote { actions: vec![QuoteAction::Create] }],
+};
+let quote_grant_request = GrantRequest::new(quote_access, None);
+let customer_quote_grant = client
+.grant()
+.request(&customer_wallet_address.auth_server, "e_grant_request)
+.await?;
+
+```
+
+
+
+
+```php
+$customerQuoteGrant = $client->grant()->request(
+ [
+ 'url' => $customerWalletAddress->authServer
+ ],
+ [
+ 'access_token' => [
+ 'access' => [
+ [
+ 'type' => 'quote',
+ 'actions' => ['create']
+ ]
+ ]
+ ]
+ ]
+);
+```
+
+
+
+
+
+```go wrap
+quoteAccess := as.AccessQuote{
+ Type: as.Quote,
+ Actions: []as.AccessQuoteActions{as.Create},
+}
+quoteAccessItem := as.AccessItem{}
+if err := quoteAccessItem.FromAccessQuote(quoteAccess); err != nil {
+ log.Fatalf("Error creating AccessItem: %v\n", err)
+}
+quoteAccessToken := struct {
+ Access as.Access `json:"access"`
+}{
+ Access: []as.AccessItem{quoteAccessItem},
+}
+
+customerQuoteGrant, err := client.Grant.Request(context.TODO(), op.GrantRequestParams{
+ URL: *customerWalletAddress.AuthServer,
+ RequestBody: as.GrantRequestWithAccessToken{AccessToken: quoteAccessToken},
+})
+if err != nil {
+ log.Fatalf("Error requesting quote grant: %v\n", err)
+}
+```
+
+
+
+
+
+```java wrap
+var customerQuoteGrant = client.auth().grant().quote(
+ customerWalletAddress
+);
+```
+
+
+
+
+
+```csharp wrap
+var customerQuoteGrant = await client.RequestGrantAsync(
+ new RequestArgs
+ {
+ Url = customerWalletAddress.AuthServer,
+ },
+ new GrantCreateBody
+ {
+ AccessToken = new AccessToken
+ {
+ Access =
+ [
+ new QuoteAccess
+ {
+ Actions = [Actions.Create]
+ }
+ ]
+ }
+ }
+);
+```
+
+
+
+
diff --git a/docs/src/content/docs/partials/code/guides/onetime-remittance-fixed-debit/_create-incoming-payment-open.mdx b/docs/src/content/docs/partials/code/guides/onetime-remittance-fixed-debit/_create-incoming-payment-open.mdx
new file mode 100644
index 00000000..7d4532fa
--- /dev/null
+++ b/docs/src/content/docs/partials/code/guides/onetime-remittance-fixed-debit/_create-incoming-payment-open.mdx
@@ -0,0 +1,102 @@
+import { Tabs, TabItem } from '@astrojs/starlight/components'
+
+
+
+
+```ts wrap
+const recipientIncomingPayment = await client.incomingPayment.create(
+ {
+ url: recipientWalletAddress.resourceServer,
+ accessToken: recipientIncomingPaymentGrant.access_token.value
+ },
+ {
+ walletAddress: recipientWalletAddress.id
+ }
+)
+```
+
+
+
+
+```rust wrap
+use open_payments::types::IncomingPaymentRequest;
+let incoming_request = IncomingPaymentRequest {
+ wallet_address: recipient_wallet_address.id.clone(),
+ incoming_amount: None,
+ expires_at: None,
+ metadata: None,
+};
+let recipient_incoming_payment = client
+ .incoming_payments()
+ .create(
+ &recipient_wallet_address.resource_server,
+ &incoming_request,
+ Some(&recipient_incoming_payment_grant.access_token.value),
+ )
+ .await?;
+```
+
+
+
+
+```php wrap
+ $recipientIncomingPayment = $client->incomingPayment()->create(
+ [
+ 'url' => $recipientWalletAddress->resourceServer,
+ 'accessToken' => $recipientIncomingPaymentGrant->access_token->value
+ ],
+ [
+ 'walletAddress' => $recipientWalletAddress->id
+ ]
+ );
+```
+
+
+
+
+
+```go wrap
+recipientIncomingPayment, err := client.IncomingPayment.Create(context.TODO(), op.IncomingPaymentCreateParams{
+ BaseURL: *recipientWalletAddress.ResourceServer,
+ AccessToken: recipientIncomingPaymentGrant.AccessToken.Value,
+ Payload: rs.CreateIncomingPaymentJSONBody{
+ WalletAddressSchema: *recipientWalletAddress.Id,
+ },
+})
+if err != nil {
+ log.Fatalf("Error creating incoming payment: %v\n", err)
+}
+```
+
+
+
+
+```java wrap
+var recipientIncomingPayment = client.payment().createIncoming(
+ recipientWalletAddress,
+ recipientIncomingPaymentGrant,
+ BigDecimal.valueOf(1700.00)
+);
+```
+
+
+
+
+
+```csharp wrap
+var recipientIncomingPayment = await client.CreateIncomingPaymentAsync(
+ new AuthRequestArgs
+ {
+ Url = recipientWalletAddress.ResourceServer,
+ AccessToken = recipientIncomingPaymentGrant.AccessToken.Value
+ },
+ new IncomingPaymentBody
+ {
+ WalletAddress = recipientWalletAddress.Id,
+ }
+);
+```
+
+
+
+
diff --git a/docs/src/content/docs/partials/code/guides/onetime-remittance-fixed-debit/_create-outgoing-payment.mdx b/docs/src/content/docs/partials/code/guides/onetime-remittance-fixed-debit/_create-outgoing-payment.mdx
new file mode 100644
index 00000000..f5a7e295
--- /dev/null
+++ b/docs/src/content/docs/partials/code/guides/onetime-remittance-fixed-debit/_create-outgoing-payment.mdx
@@ -0,0 +1,112 @@
+import { Tabs, TabItem } from '@astrojs/starlight/components'
+
+
+
+
+```ts wrap
+const senderOutgoingPayment = await client.outgoingPayment.create(
+ {
+ url: senderWalletAddress.resourceServer,
+ accessToken: senderOutgoingPaymentGrant.access_token.value
+ },
+ {
+ walletAddress: senderWalletAddress.id,
+ quoteId: senderQuote.id
+ }
+)
+```
+
+
+
+
+```rust wrap
+use open_payments::types::OutgoingPaymentRequest;
+let outgoing_request = OutgoingPaymentRequest {
+ wallet_address: sender_wallet_address.id.clone(),
+ receiver: Some(recipient_incoming_payment.id.clone()),
+ debit_amount: None,
+ receive_amount: None,
+ quote_id: Some(sender_quote.id.clone()),
+};
+let sender_outgoing_payment = client
+ .outgoing_payments()
+ .create(
+ &sender_wallet_address.resource_server,
+ &outgoing_request,
+ Some(&sender_outgoing_payment_grant.access_token.value),
+ )
+ .await?;
+```
+
+
+
+
+```php wrap
+$senderOutgoingPayment = $client->outgoingPayment()->create(
+ [
+ 'url' => $senderWalletAddress->resourceServer,
+ 'accessToken' => $senderOutgoingPaymentGrant->access_token->value
+ ],
+ [
+ 'walletAddress' => $senderWalletAddress->id,
+ 'quoteId' => $senderQuote->id
+ ]
+);
+```
+
+
+
+
+```go wrap
+var outgoingPayload rs.CreateOutgoingPaymentRequest
+if err := outgoingPayload.FromCreateOutgoingPaymentWithQuote(rs.CreateOutgoingPaymentWithQuote{
+ WalletAddressSchema: *senderWalletAddress.Id,
+ QuoteId: *senderQuote.Id,
+}); err != nil {
+ log.Fatalf("Error creating payload: %v\n", err)
+}
+
+senderOutgoingPayment, err := client.OutgoingPayment.Create(context.TODO(), op.OutgoingPaymentCreateParams{
+ BaseURL: senderWalletAddress.ResourceServer,
+ AccessToken: senderOutgoingPaymentGrant.AccessToken.Value,
+ Payload: outgoingPayload,
+})
+if err != nil {
+ log.Fatalf("Error creating outgoing payment: %v\n", err)
+}
+
+```
+
+
+
+
+```java wrap
+var senderOutgoingPayment = client.payment().createOutgoing(
+ senderOutgoingPaymentGrant,
+ senderWalletAddress,
+ senderQuote
+);
+```
+
+
+
+
+
+```csharp wrap
+var senderOutgoingPayment = await client.CreateOutgoingPaymentAsync(
+ new AuthRequestArgs
+ {
+ Url = senderWalletAddress.ResourceServer,
+ AccessToken = senderOutgoingPaymentGrant.AccessToken.Value
+ },
+ new OutgoingPaymentBodyFromQuote
+ {
+ WalletAddress = senderWalletAddress.Id,
+ QuoteId = senderQuote.Id,
+ }
+);
+```
+
+
+
+
diff --git a/docs/src/content/docs/partials/code/guides/onetime-remittance-fixed-debit/_create-quote-debit-amount.mdx b/docs/src/content/docs/partials/code/guides/onetime-remittance-fixed-debit/_create-quote-debit-amount.mdx
new file mode 100644
index 00000000..c4c86136
--- /dev/null
+++ b/docs/src/content/docs/partials/code/guides/onetime-remittance-fixed-debit/_create-quote-debit-amount.mdx
@@ -0,0 +1,133 @@
+import { Tabs, TabItem } from '@astrojs/starlight/components'
+
+
+
+ ```ts wrap
+ 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
+ }
+ }
+ )
+```
+
+
+
+
+```rust wrap
+use open_payments::types::{QuoteRequest, QuoteMethod, Amount};
+let quote_request = QuoteRequest {
+ method: QuoteMethod::Ilp,
+ wallet_address: Some(sender_wallet_address.id.clone()),
+ receiver: Some(recipient_incoming_payment.id.clone()),
+ debit_amount: Some(Amount {
+ value: "10000".into(),
+ asset_code: "USD".into(),
+ asset_scale: 2,
+ }),
+ receive_amount: None,
+};
+let sender_quote = client
+ .quotes()
+ .create(
+ &sender_wallet_address.resource_server,
+ "e_request,
+ Some(&sender_quote_grant.access_token.value),
+ )
+ .await?;
+```
+
+
+
+
+```php wrap
+$senderQuote = $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
+ ]
+ ]
+);
+```
+
+
+
+
+```go wrap
+senderQuote, err := client.Quote.Create(context.TODO(), op.QuoteCreateParams{
+ BaseURL: *senderWalletAddress.ResourceServer,
+ AccessToken: senderQuoteGrant.AccessToken.Value,
+ Payload: rs.CreateQuoteJSONBody1{
+ WalletAddressSchema: *senderWalletAddress.Id,
+ Receiver: *recipientIncomingPayment.Id,
+ Method: "ilp",
+ DebitAmount: rs.Amount{
+ Value: "10000",
+ AssetCode: "USD",
+ AssetScale: 2,
+ },
+ },
+})
+if err != nil {
+ log.Fatalf("Error creating quote: %v\n", err)
+}
+```
+
+
+
+
+```java wrap
+var senderQuote = client.quote().create(
+ senderQuoteGrant.getAccess().getToken(),
+ senderWalletAddress,
+ recipientIncomingPayment,
+ Optional.of(
+ Amount.build(BigDecimal.valueOf(100.00), "USD", 2)
+ ),
+ Optional.empty()
+);
+```
+
+
+
+
+
+```csharp wrap
+var senderQuote = await client.CreateQuoteAsync(
+ new AuthRequestArgs
+ {
+ Url = senderWalletAddress.ResourceServer,
+ AccessToken = senderQuoteGrant.AccessToken.Value
+ },
+ new QuoteBodyWithDebitAmount
+ {
+ Method = PaymentMethod.Ilp,
+ WalletAddress = senderWalletAddress.Id,
+ Receiver = recipientIncomingPayment.Id,
+ DebitAmount = new Amount("10000", "USD", 2)
+ }
+);
+```
+
+
+
+
diff --git a/docs/src/content/docs/partials/code/guides/onetime-remittance-fixed-debit/_get-wallet-address.mdx b/docs/src/content/docs/partials/code/guides/onetime-remittance-fixed-debit/_get-wallet-address.mdx
new file mode 100644
index 00000000..f9153202
--- /dev/null
+++ b/docs/src/content/docs/partials/code/guides/onetime-remittance-fixed-debit/_get-wallet-address.mdx
@@ -0,0 +1,75 @@
+import { Tabs, TabItem } from '@astrojs/starlight/components'
+
+
+
+
+```ts
+const senderWalletAddress = await client.walletAddress.get({
+ url: 'https://cloudninebank.example.com/sender'
+})
+const recipientWalletAddress = await client.walletAddress.get({
+ url: 'https://happylifebank.example.com/recipient'
+})
+```
+
+
+
+
+```rust wrap
+let sender_wallet_address = client.wallet_address().get("https://cloudninebank.example.com/sender").await?;
+let recipient_wallet_address = client.wallet_address().get("https://happylifebank.example.com/recipient").await?;
+```
+
+
+
+
+
+```php wrap
+$senderWalletAddress = $client->walletAddress()->get([
+ 'url' => 'https://cloudninebank.example.com/sender'
+]);
+$recipientWalletAddress = $client->walletAddress()->get([
+ 'url' => 'https://happylifebank.example.com/recipient'
+]);
+```
+
+
+
+
+
+```go wrap
+senderWalletAddress, err := client.WalletAddress.Get(context.TODO(), op.WalletAddressGetParams{
+ URL: "https://cloudninebank.example.com/sender",
+})
+if err != nil {
+ log.Fatalf("Error fetching sender wallet address: %v\n", err)
+}
+
+recipientWalletAddress, err := client.WalletAddress.Get(context.TODO(), op.WalletAddressGetParams{
+ URL: "https://happylifebank.example.com/recipient",
+})
+if err != nil {
+ log.Fatalf("Error fetching recipient wallet address: %v\n", err)
+}
+```
+
+
+
+
+ ```java wrap
+ var senderWalletAddress = client.walletAddress().get("https://cloudninebank.example.com/sender");
+ var recipientWalletAddress = client.walletAddress().get("https://happylifebank.example.com/recipient");
+ ```
+
+
+
+
+
+```csharp wrap
+var senderWalletAddress = await client.GetWalletAddressAsync("https://cloudninebank.example.com/sender");
+var recipientWalletAddress = await client.GetWalletAddressAsync("https://happylifebank.example.com/recipient");
+```
+
+
+
+
diff --git a/docs/src/content/docs/partials/code/guides/onetime-remittance-fixed-debit/_grant-request-incoming-payment.mdx b/docs/src/content/docs/partials/code/guides/onetime-remittance-fixed-debit/_grant-request-incoming-payment.mdx
new file mode 100644
index 00000000..a8907dba
--- /dev/null
+++ b/docs/src/content/docs/partials/code/guides/onetime-remittance-fixed-debit/_grant-request-incoming-payment.mdx
@@ -0,0 +1,122 @@
+import { Tabs, TabItem } from '@astrojs/starlight/components'
+
+
+
+
+```ts wrap
+const recipientIncomingPaymentGrant = await client.grant.request(
+ {
+ url: recipientWalletAddress.authServer
+ },
+ {
+ access_token: {
+ access: [
+ {
+ type: 'incoming-payment',
+ actions: ['create']
+ }
+ ]
+ }
+ }
+)
+```
+
+
+
+
+```rust wrap
+use open_payments::types::{AccessTokenRequest, AccessItem, IncomingPaymentAction, GrantRequest};
+let incoming_access = AccessTokenRequest {
+ access: vec![AccessItem::IncomingPayment { actions: vec![IncomingPaymentAction::Create, IncomingPaymentAction::Complete], identifier: None }],
+};
+let incoming_grant_request = GrantRequest::new(incoming_access, None);
+let recipient_incoming_payment_grant = client
+ .grant()
+ .request(&recipient_wallet_address.auth_server, &incoming_grant_request)
+ .await?;
+```
+
+
+
+
+
+```php wrap
+$recipientIncomingPaymentGrant = $client->grant()->request([
+ 'url' => $recipientWalletAddress->authServer
+], [
+ 'access_token' => [
+ 'access' => [
+ [
+ 'type' => 'incoming-payment',
+ 'actions' => ['create']
+ ]
+ ]
+ ]
+]);
+```
+
+
+
+
+
+```go wrap
+incomingAccess := as.AccessIncoming{
+ Type: as.IncomingPayment,
+ Actions: []as.AccessIncomingActions{as.AccessIncomingActionsCreate},
+}
+accessItem := as.AccessItem{}
+if err := accessItem.FromAccessIncoming(incomingAccess); err != nil {
+ log.Fatalf("Error creating AccessItem: %v\n", err)
+}
+accessToken := struct {
+ Access as.Access `json:"access"`
+}{
+ Access: []as.AccessItem{accessItem},
+}
+
+recipientIncomingPaymentGrant, err := client.Grant.Request(context.TODO(), op.GrantRequestParams{
+ URL: *recipientWalletAddress.AuthServer,
+ RequestBody: as.GrantRequestWithAccessToken{AccessToken: accessToken},
+})
+if err != nil {
+ log.Fatalf("Error requesting incoming payment grant: %v\n", err)
+}
+
+```
+
+
+
+
+```java wrap
+var recipientIncomingPaymentGrant = client.auth().grant().incomingPayment(recipientWalletAddress);
+```
+
+
+
+
+
+```csharp wrap
+var recipientIncomingPaymentGrant = await client.RequestGrantAsync(
+ new RequestArgs
+ {
+ Url = recipientWalletAddress.AuthServer,
+ },
+ new GrantCreateBody
+ {
+ AccessToken = new AccessToken
+ {
+ Access =
+ [
+ new IncomingAccess
+ {
+ Actions = [Actions.Create]
+ }
+ ]
+ }
+ }
+);
+```
+
+
+
+
diff --git a/docs/src/content/docs/partials/code/guides/onetime-remittance-fixed-debit/_grant-request-outgoing-payment.mdx b/docs/src/content/docs/partials/code/guides/onetime-remittance-fixed-debit/_grant-request-outgoing-payment.mdx
new file mode 100644
index 00000000..527d61a4
--- /dev/null
+++ b/docs/src/content/docs/partials/code/guides/onetime-remittance-fixed-debit/_grant-request-outgoing-payment.mdx
@@ -0,0 +1,235 @@
+import { Tabs, TabItem } from '@astrojs/starlight/components'
+
+
+
+
+
+```ts wrap
+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
+ }
+ }
+ }
+)
+```
+
+
+
+
+```rust wrap
+use open_payments::types::{
+ AccessTokenRequest,
+ AccessItem,
+ OutgoingPaymentAction,
+ AccessLimits,
+ Amount,
+ InteractRequest,
+ InteractStart,
+ InteractFinish,
+ InteractFinishMethod,
+ GrantRequest,
+};
+
+let outgoing_access = AccessTokenRequest {
+access: vec![AccessItem::OutgoingPayment {
+identifier: Some(sender_wallet_address.id.clone()),
+actions: vec![OutgoingPaymentAction::Create],
+limits: Some(AccessLimits {
+debit_amount: Some(Amount {
+value: "10000".into(),
+asset_code: "USD".into(),
+asset_scale: 2,
+}),
+..Default::default()
+}),
+}],
+};
+
+let interact = InteractRequest {
+start: Some(vec![InteractStart::Redirect]),
+finish: Some(InteractFinish {
+method: InteractFinishMethod::Redirect,
+uri: Some("https://myapp.example.com/finish/{...}".into()),
+nonce: Some("NONCE".into()),
+}),
+};
+
+let outgoing_grant_request = GrantRequest::new(outgoing_access, Some(interact));
+
+let pending_sender_outgoing_payment_grant = client
+.grant()
+.request(&sender_wallet_address.auth_server, &outgoing_grant_request)
+.await?;
+
+```
+
+
+
+
+
+```php wrap
+$pendingSenderOutgoingPaymentGrant = $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'
+ ]
+ ]
+ ]
+);
+```
+
+
+
+
+
+```go wrap
+outgoingAccess := as.AccessOutgoing{
+ Type: as.OutgoingPayment,
+ Actions: []as.AccessOutgoingActions{as.AccessOutgoingActionsCreate},
+ Identifier: *senderWalletAddress.Id,
+ Limits: &as.LimitsOutgoing{
+ DebitAmount: &as.Amount{
+ Value: "10000",
+ AssetCode: "USD",
+ AssetScale: 2,
+ },
+ },
+}
+outgoingAccessItem := as.AccessItem{}
+if err := outgoingAccessItem.FromAccessOutgoing(outgoingAccess); err != nil {
+ log.Fatalf("Error creating AccessItem: %v\n", err)
+}
+outgoingAccessToken := struct {
+ Access as.Access `json:"access"`
+}{
+ Access: []as.AccessItem{outgoingAccessItem},
+}
+interact := &as.InteractRequest{
+ Start: []as.InteractRequestStart{as.InteractRequestStartRedirect},
+ Finish: &as.InteractRequestFinish{
+ Method: as.Redirect,
+ Uri: "https://myapp.example.com/finish/{...}",
+ Nonce: NONCE,
+ },
+}
+
+pendingSenderOutgoingPaymentGrant, err := client.Grant.Request(context.TODO(), op.GrantRequestParams{
+ URL: *senderWalletAddress.AuthServer,
+ RequestBody: as.GrantRequestWithAccessToken{
+ AccessToken: outgoingAccessToken,
+ Interact: interact,
+ },
+})
+if err != nil {
+ log.Fatalf("Error requesting outgoing payment grant: %v\n", err)
+}
+```
+
+
+
+
+```java wrap
+ var debitAmount = Amount.build(BigDecimal.valueOf(100.00), "USD", 2);
+ var urlToOpen = "https://myapp.example.com/finish/{...}";
+
+var opContinueInteract = client.auth().grant().continuation(
+senderWalletAddress,
+debitAmount,
+URI.create(urlToOpen),
+"NONCE"
+);
+
+```
+
+
+
+
+
+```csharp wrap
+var pendingSenderOutgoingPaymentGrant = await client.RequestGrantAsync(
+ new RequestArgs
+ {
+ Url = senderWalletAddress.AuthServer,
+ },
+ new GrantCreateBodyWithInteract
+ {
+ AccessToken = new AccessToken
+ {
+ Access =
+ [
+ new OutgoingAccess
+ {
+ Identifier = senderWalletAddress.Id,
+ Actions = [Actions.Create],
+ Limits = new OutgoingAccessLimits
+ {
+ DebitAmount = new AuthAmount("10000", "USD", 2)
+ }
+ }
+ ]
+ },
+ Interact = new InteractRequest
+ {
+ Start = [Start.Redirect],
+ Finish = new Finish
+ {
+ Method = FinishMethod.Redirect,
+ Uri = new Uri("https://localhost"), // where to redirect your user after they've completed the interaction
+ Nonce = NONCE
+ }
+ }
+ }
+);
+```
+
+
+
+
diff --git a/docs/src/content/docs/partials/code/guides/onetime-remittance-fixed-debit/_grant-request-quote.mdx b/docs/src/content/docs/partials/code/guides/onetime-remittance-fixed-debit/_grant-request-quote.mdx
new file mode 100644
index 00000000..f46477c7
--- /dev/null
+++ b/docs/src/content/docs/partials/code/guides/onetime-remittance-fixed-debit/_grant-request-quote.mdx
@@ -0,0 +1,123 @@
+import { Tabs, TabItem } from '@astrojs/starlight/components'
+
+
+
+
+ ```ts wrap
+ const senderQuoteGrant = await client.grant.request(
+ {
+ url: senderWalletAddress.authServer
+ },
+ {
+ access_token: {
+ access: [
+ {
+ type: 'quote',
+ actions: ['create']
+ }
+ ]
+ }
+ }
+ )
+ ```
+
+
+
+
+```rust wrap
+use open_payments::types::{AccessTokenRequest, AccessItem, QuoteAction, GrantRequest};
+let quote_access = AccessTokenRequest {
+ access: vec![AccessItem::Quote { actions: vec![QuoteAction::Create] }],
+};
+let quote_grant_request = GrantRequest::new(quote_access, None);
+let sender_quote_grant = client
+ .grant()
+ .request(&sender_wallet_address.auth_server, "e_grant_request)
+ .await?;
+```
+
+
+
+
+```php wrap
+$senderQuoteGrant = $client->grant()->request(
+ [
+ 'url' => $senderWalletAddress->authServer
+ ],
+ [
+ 'access_token' => [
+ 'access' => [
+ [
+ 'type' => 'quote',
+ 'actions' => ['create']
+ ]
+ ]
+ ]
+ ]
+);
+```
+
+
+
+
+```go wrap
+quoteAccess := as.AccessQuote{
+ Type: as.Quote,
+ Actions: []as.AccessQuoteActions{as.Create},
+}
+quoteAccessItem := as.AccessItem{}
+if err := quoteAccessItem.FromAccessQuote(quoteAccess); err != nil {
+ log.Fatalf("Error creating AccessItem: %v\n", err)
+}
+quoteAccessToken := struct {
+ Access as.Access `json:"access"`
+}{
+ Access: []as.AccessItem{quoteAccessItem},
+}
+
+senderQuoteGrant, err := client.Grant.Request(context.TODO(), op.GrantRequestParams{
+ URL: senderWalletAddress.AuthServer,
+ RequestBody: as.GrantRequestWithAccessToken{AccessToken: quoteAccessToken},
+})
+if err != nil {
+ log.Fatalf("Error requesting quote grant: %v\n", err)
+}
+
+```
+
+
+
+
+```java wrap
+var senderQuoteGrant = client.auth().grant().quote(senderWalletAddress);
+```
+
+
+
+
+
+```csharp wrap
+var senderQuoteGrant = await client.RequestGrantAsync(
+ new RequestArgs
+ {
+ Url = senderWalletAddress.AuthServer,
+ },
+ new GrantCreateBody
+ {
+ AccessToken = new AccessToken
+ {
+ Access =
+ [
+ new QuoteAccess
+ {
+ Actions = [Actions.Create]
+ }
+ ]
+ }
+ }
+);
+```
+
+
+
+
diff --git a/docs/src/content/docs/partials/code/guides/onetime-remittance-fixed-debit/_request-a-grant-continuation.mdx b/docs/src/content/docs/partials/code/guides/onetime-remittance-fixed-debit/_request-a-grant-continuation.mdx
new file mode 100644
index 00000000..412286fa
--- /dev/null
+++ b/docs/src/content/docs/partials/code/guides/onetime-remittance-fixed-debit/_request-a-grant-continuation.mdx
@@ -0,0 +1,98 @@
+import { Tabs, TabItem } from '@astrojs/starlight/components'
+
+
+
+
+ ```ts wrap
+ const senderOutgoingPaymentGrant = await client.grant.continue(
+ {
+ url: pendingSenderOutgoingPaymentGrant.continue.uri,
+ accessToken: pendingSenderOutgoingPaymentGrant.continue.access_token.value
+ },
+ {
+ interact_ref: interactRef
+ }
+ )
+ ```
+
+
+
+
+```rust wrap
+let continue_field = match &pending_sender_outgoing_payment_grant.continue_field {
+ Some(c) => c,
+ None => {
+ eprintln!("Missing continue field on pending grant");
+ return Ok(());
+ }
+};
+let sender_outgoing_payment_grant = client
+ .grant()
+ .continue_grant(
+ &continue_field.uri,
+ &interact_ref,
+ Some(&continue_field.access_token.value),
+ )
+ .await?;
+```
+
+
+
+
+```php wrap
+$senderOutgoingPaymentGrant = $client->grant()->continue(
+ [
+ 'url' => $pendingSenderOutgoingPaymentGrant->continue->uri,
+ 'accessToken' => $pendingSenderOutgoingPaymentGrant->continue->access_token->value
+ ],
+ [
+ 'interact_ref' => $interactRef
+ ]
+);
+```
+
+
+
+
+```go wrap
+senderOutgoingPaymentGrant, err := client.Grant.Continue(context.TODO(), op.GrantContinueParams{
+ URL: pendingSenderOutgoingPaymentGrant.Continue.Uri,
+ AccessToken: pendingSenderOutgoingPaymentGrant.Continue.AccessToken.Value,
+ InteractRef: INTERACT_REF,
+})
+if err != nil {
+ log.Fatalf("Error continuing grant: %v\n", err)
+}
+```
+
+
+
+
+```java wrap
+var senderOutgoingPaymentGrant = client.auth().grant().finalize(
+ opContinueInteract,
+ interactRef
+);
+```
+
+
+
+
+
+```csharp wrap
+var senderOutgoingPaymentGrant = await client.ContinueGrantAsync(
+ new AuthRequestArgs
+ {
+ Url = pendingSenderOutgoingPaymentGrant.Continue.Uri,
+ AccessToken = pendingSenderOutgoingPaymentGrant.Continue.AccessToken.Value
+ },
+ new GrantContinueBody
+ {
+ InteractRef = interactRef
+ }
+);
+```
+
+
+
+
diff --git a/docs/src/content/docs/partials/code/guides/onetime-remittance-fixed-receive/_create-incoming-payment.mdx b/docs/src/content/docs/partials/code/guides/onetime-remittance-fixed-receive/_create-incoming-payment.mdx
new file mode 100644
index 00000000..cd1a4feb
--- /dev/null
+++ b/docs/src/content/docs/partials/code/guides/onetime-remittance-fixed-receive/_create-incoming-payment.mdx
@@ -0,0 +1,105 @@
+import { Tabs, TabItem } from '@astrojs/starlight/components'
+
+
+
+
+```ts wrap
+const recipientIncomingPayment = await client.incomingPayment.create(
+ {
+ url: recipientWalletAddress.resourceServer,
+ accessToken: recipientIncomingPaymentGrant.access_token.value
+ },
+ {
+ walletAddress: recipientWalletAddress.id
+ }
+)
+```
+
+
+
+
+```rust wrap
+use open_payments::types::IncomingPaymentRequest;
+
+let incoming_request = IncomingPaymentRequest {
+wallet_address: recipient_wallet_address.id.clone(),
+incoming_amount: None,
+expires_at: None,
+metadata: None,
+};
+let recipient_incoming_payment = client
+.incoming_payments()
+.create(
+&recipient_wallet_address.resource_server,
+&incoming_request,
+Some(&recipient_incoming_payment_grant.access_token.value),
+)
+.await?;
+
+```
+
+
+
+
+
+```php wrap
+$recipientIncomingPayment = $client->incomingPayment()->create(
+ [
+ 'url' => $recipientWalletAddress->resourceServer,
+ 'accessToken' => $recipientIncomingPaymentGrant->access_token->value
+ ],
+ [
+ 'walletAddress' => $recipientWalletAddress->id,
+ ]
+);
+```
+
+
+
+
+
+```go wrap
+recipientIncomingPayment, err := client.IncomingPayment.Create(context.TODO(), op.IncomingPaymentCreateParams{
+ BaseURL: *recipientWalletAddress.ResourceServer,
+ AccessToken: recipientIncomingPaymentGrant.AccessToken.Value,
+ Payload: rs.CreateIncomingPaymentJSONBody{
+ WalletAddressSchema: *recipientWalletAddress.Id,
+ },
+})
+if err != nil {
+ log.Fatalf("Error creating incoming payment: %v\n", err)
+}
+```
+
+
+
+
+```java wrap
+var recipientIncomingPayment = client.payment().createIncoming(
+ recipientWalletAddress,
+ recipientIncomingPaymentGrant,
+ BigDecimal.valueOf(5000.00)
+);
+```
+
+
+
+
+
+```csharp wrap
+var recipientIncomingPayment = await client.CreateIncomingPaymentAsync(
+ new AuthRequestArgs
+ {
+ Url = recipientWalletAddress.ResourceServer,
+ AccessToken = recipientIncomingPaymentGrant.AccessToken.Value
+ },
+ new IncomingPaymentBody
+ {
+ WalletAddress = recipientWalletAddress.Id,
+ }
+);
+```
+
+
+
+
diff --git a/docs/src/content/docs/partials/code/guides/onetime-remittance-fixed-receive/_create-outgoing-payment.mdx b/docs/src/content/docs/partials/code/guides/onetime-remittance-fixed-receive/_create-outgoing-payment.mdx
new file mode 100644
index 00000000..01d430f6
--- /dev/null
+++ b/docs/src/content/docs/partials/code/guides/onetime-remittance-fixed-receive/_create-outgoing-payment.mdx
@@ -0,0 +1,113 @@
+import { Tabs, TabItem } from '@astrojs/starlight/components'
+
+
+
+
+```ts wrap
+const senderOutgoingPayment = await client.outgoingPayment.create(
+ {
+ url: senderWalletAddress.resourceServer,
+ accessToken: senderOutgoingPaymentGrant.access_token.value
+ },
+ {
+ walletAddress: senderWalletAddress.id,
+ quoteId: senderQuote.id
+ }
+)
+```
+
+
+
+
+```rust wrap
+use open_payments::types::OutgoingPaymentRequest;
+let outgoing_request = OutgoingPaymentRequest {
+ wallet_address: sender_wallet_address.id.clone(),
+ receiver: Some(recipient_incoming_payment.id.clone()),
+ debit_amount: None,
+ receive_amount: None,
+ quote_id: Some(sender_quote.id.clone()),
+};
+let sender_outgoing_payment = client
+ .outgoing_payments()
+ .create(
+ &sender_wallet_address.resource_server,
+ &outgoing_request,
+ Some(&sender_outgoing_payment_grant.access_token.value),
+ )
+ .await?;
+```
+
+
+
+
+
+```php wrap
+ $senderOutgoingPayment = $client->outgoingPayment()->create(
+ [
+ 'url' => $senderWalletAddress->resourceServer,
+ 'accessToken' => $senderOutgoingPaymentGrant->access_token->value
+ ],
+ [
+ 'walletAddress' => $senderWalletAddress->id,
+ 'quoteId' => $senderQuote->id
+ ]
+);
+```
+
+
+
+
+
+```go wrap
+var outgoingPayload rs.CreateOutgoingPaymentRequest
+if err := outgoingPayload.FromCreateOutgoingPaymentWithQuote(rs.CreateOutgoingPaymentWithQuote{
+ WalletAddressSchema: *senderWalletAddress.Id,
+ QuoteId: *senderQuote.Id,
+}); err != nil {
+ log.Fatalf("Error creating payload: %v\n", err)
+}
+
+senderOutgoingPayment, err := client.OutgoingPayment.Create(context.TODO(), op.OutgoingPaymentCreateParams{
+ BaseURL: *senderWalletAddress.ResourceServer,
+ AccessToken: senderOutgoingPaymentGrant.AccessToken.Value,
+ Payload: outgoingPayload,
+})
+if err != nil {
+ log.Fatalf("Error creating outgoing payment: %v\n", err)
+}
+```
+
+
+
+
+```java wrap
+var senderOutgoingPayment = client.payment().createOutgoing(
+ senderOutgoingPaymentGrant,
+ senderWalletAddress,
+ senderQuote
+);
+```
+
+
+
+
+
+```csharp wrap
+var senderOutgoingPayment = await client.CreateOutgoingPaymentAsync(
+ new AuthRequestArgs
+ {
+ Url = senderWalletAddress.ResourceServer,
+ AccessToken = senderOutgoingPaymentGrant.AccessToken.Value
+ },
+ new OutgoingPaymentBodyFromQuote
+ {
+ WalletAddress = senderWalletAddress.Id,
+ QuoteId = senderQuote.Id,
+ }
+);
+```
+
+
+
+
diff --git a/docs/src/content/docs/partials/code/guides/onetime-remittance-fixed-receive/_create-quote-ilp.mdx b/docs/src/content/docs/partials/code/guides/onetime-remittance-fixed-receive/_create-quote-ilp.mdx
new file mode 100644
index 00000000..68649c64
--- /dev/null
+++ b/docs/src/content/docs/partials/code/guides/onetime-remittance-fixed-receive/_create-quote-ilp.mdx
@@ -0,0 +1,134 @@
+import { Tabs, TabItem } from '@astrojs/starlight/components'
+
+
+
+
+```ts wrap
+const senderQuote = await client.quote.create(
+ {
+ url: senderWalletAddress.resourceServer,
+ accessToken: senderQuoteGrant.access_token.value
+ },
+ {
+ method: 'ilp',
+ walletAddress: senderWalletAddress.id,
+ receiver: recipientIncomingPayment.id,
+ receiveAmount: {
+ value: '500000',
+ assetCode: 'MXN',
+ assetScale: 2
+ }
+ }
+)
+```
+
+
+
+
+```rust wrap
+use open_payments::types::{QuoteRequest, QuoteMethod, Amount};
+
+let quote_request = QuoteRequest {
+method: QuoteMethod::Ilp,
+wallet_address: Some(sender_wallet_address.id.clone()),
+receiver: Some(recipient_incoming_payment.id.clone()),
+debit_amount: None,
+receive_amount: Some(Amount { value: "500000".into(), asset_code: "MXN".into(), asset_scale: 2 }),
+};
+let sender_quote = client
+.quotes()
+.create(
+&sender_wallet_address.resource_server,
+"e_request,
+Some(&sender_quote_grant.access_token.value),
+)
+.await?;
+
+```
+
+
+
+
+
+```php wrap
+$senderQuote = $client->quote()->create(
+ [
+ 'url' => $senderWalletAddress->resourceServer,
+ 'accessToken' => $senderQuoteGrant->access_token->value
+ ],
+ [
+ 'method' => 'ilp',
+ 'walletAddress' => $senderWalletAddress->id,
+ 'receiver' => $recipientIncomingPayment->id,
+ 'receiveAmount' => [
+ 'value' => '500000',
+ 'assetCode' => 'MXN',
+ 'assetScale' => 2
+ ]
+ ]
+);
+```
+
+
+
+
+
+```go wrap
+senderQuote, err := client.Quote.Create(context.TODO(), op.QuoteCreateParams{
+ BaseURL: *senderWalletAddress.ResourceServer,
+ AccessToken: senderQuoteGrant.AccessToken.Value,
+ Payload: rs.CreateQuoteJSONBody2{
+ WalletAddressSchema: *senderWalletAddress.Id,
+ Receiver: *recipientIncomingPayment.Id,
+ Method: "ilp",
+ ReceiveAmount: rs.Amount{
+ Value: "500000",
+ AssetCode: "MXN",
+ AssetScale: 2,
+ },
+ },
+})
+if err != nil {
+ log.Fatalf("Error creating quote: %v\n", err)
+}
+```
+
+
+
+
+```java wrap
+var senderQuote = client.quote().create(
+ senderQuoteGrant.getAccess().getToken(),
+ senderWalletAddress,
+ recipientIncomingPayment,
+ Optional.empty(),
+ Optional.of(
+ Amount.build(BigDecimal.valueOf(5000.00), "MXN", 2)
+ )
+);
+```
+
+
+
+
+
+```csharp wrap
+var senderQuote = await client.CreateQuoteAsync(
+ new AuthRequestArgs
+ {
+ Url = senderWalletAddress.ResourceServer,
+ AccessToken = senderQuoteGrant.AccessToken.Value
+ },
+ new QuoteBodyWithReceiveAmount
+ {
+ Method = PaymentMethod.Ilp,
+ WalletAddress = senderWalletAddress.Id,
+ Receiver = recipientIncomingPayment.Id,
+ ReceiveAmount = new Amount("500000", "MXN", 2)
+ }
+);
+```
+
+
+
+
diff --git a/docs/src/content/docs/partials/code/guides/onetime-remittance-fixed-receive/_get-wallet-address.mdx b/docs/src/content/docs/partials/code/guides/onetime-remittance-fixed-receive/_get-wallet-address.mdx
new file mode 100644
index 00000000..ee9287f5
--- /dev/null
+++ b/docs/src/content/docs/partials/code/guides/onetime-remittance-fixed-receive/_get-wallet-address.mdx
@@ -0,0 +1,75 @@
+import { Tabs, TabItem } from '@astrojs/starlight/components'
+
+
+
+
+```ts wrap
+const senderWalletAddress = await client.walletAddress.get({
+ url: 'https://cloudninebank.example.com/sender'
+})
+const recipientWalletAddress = await client.walletAddress.get({
+ url: 'https://happylifebank.example.com/recipient'
+})
+```
+
+
+
+
+```rust wrap
+let sender_wallet_address = client.wallet_address().get("https://cloudninebank.example.com/sender").await?;
+let recipient_wallet_address = client.wallet_address().get("https://happylifebank.example.com/recipient").await?;
+```
+
+
+
+
+
+```php wrap
+$senderWalletAddress = $client->walletAddress()->get([
+ 'url' => 'https://cloudninebank.example.com/sender'
+]);
+$recipientWalletAddress = $client->walletAddress()->get([
+ 'url' => 'https://happylifebank.example.com/recipient'
+]);
+```
+
+
+
+
+
+```go wrap
+senderWalletAddress, err := client.WalletAddress.Get(context.TODO(), op.WalletAddressGetParams{
+ URL: "https://cloudninebank.example.com/sender",
+})
+if err != nil {
+ log.Fatalf("Error fetching sender wallet address: %v\n", err)
+}
+
+recipientWalletAddress, err := client.WalletAddress.Get(context.TODO(), op.WalletAddressGetParams{
+ URL: "https://happylifebank.example.com/recipient",
+})
+if err != nil {
+ log.Fatalf("Error fetching recipient wallet address: %v\n", err)
+}
+```
+
+
+
+
+```java wrap
+var senderWalletAddress = client.walletAddress().get("https://cloudninebank.example.com/sender");
+var recipientWalletAddress = client.walletAddress().get("https://happylifebank.example.com/recipient");
+```
+
+
+
+
+
+```csharp wrap
+var senderWalletAddress = await client.GetWalletAddressAsync("https://cloudninebank.example.com/sender");
+var recipientWalletAddress = await client.GetWalletAddressAsync("https://happylifebank.example.com/recipient");
+```
+
+
+
+
diff --git a/docs/src/content/docs/partials/code/guides/onetime-remittance-fixed-receive/_grant-request-incoming-payment.mdx b/docs/src/content/docs/partials/code/guides/onetime-remittance-fixed-receive/_grant-request-incoming-payment.mdx
new file mode 100644
index 00000000..0efa52d8
--- /dev/null
+++ b/docs/src/content/docs/partials/code/guides/onetime-remittance-fixed-receive/_grant-request-incoming-payment.mdx
@@ -0,0 +1,126 @@
+import { Tabs, TabItem } from '@astrojs/starlight/components'
+
+
+
+
+```ts wrap
+const recipientIncomingPaymentGrant = await client.grant.request(
+ {
+ url: recipientWalletAddress.authServer
+ },
+ {
+ access_token: {
+ access: [
+ {
+ type: 'incoming-payment',
+ actions: ['create']
+ }
+ ]
+ }
+ }
+)
+```
+
+
+
+
+```rust wrap
+use open_payments::types::{AccessTokenRequest, AccessItem, IncomingPaymentAction, GrantRequest};
+
+let incoming_access = AccessTokenRequest {
+access: vec![AccessItem::IncomingPayment { actions: vec![IncomingPaymentAction::Create, IncomingPaymentAction::Complete], identifier: None }],
+};
+let incoming_grant_request = GrantRequest::new(incoming_access, None);
+let recipient_incoming_payment_grant = client
+.grant()
+.request(&recipient_wallet_address.auth_server, &incoming_grant_request)
+.await?;
+
+```
+
+
+
+
+
+```php wrap
+$recipientIncomingPaymentGrant = $client->grant()->request(
+ [
+ 'url' => $recipientWalletAddress->authServer
+ ],
+ [
+ 'access_token' => [
+ 'access' => [
+ [
+ 'type' => 'incoming-payment',
+ 'actions' => ['create']
+ ],
+ ],
+ ],
+ ]
+);
+```
+
+
+
+
+
+```go wrap
+incomingAccess := as.AccessIncoming{
+ Type: as.IncomingPayment,
+ Actions: []as.AccessIncomingActions{as.AccessIncomingActionsCreate},
+}
+accessItem := as.AccessItem{}
+if err := accessItem.FromAccessIncoming(incomingAccess); err != nil {
+ log.Fatalf("Error creating AccessItem: %v\n", err)
+}
+accessToken := struct {
+ Access as.Access `json:"access"`
+}{
+ Access: []as.AccessItem{accessItem},
+}
+
+recipientIncomingPaymentGrant, err := client.Grant.Request(context.TODO(), op.GrantRequestParams{
+ URL: *recipientWalletAddress.AuthServer,
+ RequestBody: as.GrantRequestWithAccessToken{AccessToken: accessToken},
+})
+if err != nil {
+ log.Fatalf("Error requesting incoming payment grant: %v\n", err)
+}
+```
+
+
+
+
+```java wrap
+var recipientIncomingPaymentGrant = client.auth().grant().incomingPayment(recipientWalletAddress);
+```
+
+
+
+
+
+```csharp wrap
+var recipientIncomingPaymentGrant = await client.RequestGrantAsync(
+ new RequestArgs
+ {
+ Url = recipientWalletAddress.AuthServer,
+ },
+ new GrantCreateBody
+ {
+ AccessToken = new AccessToken
+ {
+ Access =
+ [
+ new IncomingAccess
+ {
+ Actions = [Actions.Create]
+ }
+ ]
+ }
+ }
+);
+```
+
+
+
+
diff --git a/docs/src/content/docs/partials/code/guides/onetime-remittance-fixed-receive/_grant-request-outgoing-payment.mdx b/docs/src/content/docs/partials/code/guides/onetime-remittance-fixed-receive/_grant-request-outgoing-payment.mdx
new file mode 100644
index 00000000..a1b72f22
--- /dev/null
+++ b/docs/src/content/docs/partials/code/guides/onetime-remittance-fixed-receive/_grant-request-outgoing-payment.mdx
@@ -0,0 +1,226 @@
+import { Tabs, TabItem } from '@astrojs/starlight/components'
+
+
+
+
+```ts wrap
+const pendingSenderOutgoingPaymentGrant = await client.grant.request(
+ {
+ url: senderWalletAddress.authServer
+ },
+ {
+ access_token: {
+ access: [
+ {
+ identifier: senderWalletAddress.id,
+ type: 'outgoing-payment',
+ actions: ['create'],
+ limits: {
+ receiveAmount: {
+ assetCode: 'MXN',
+ assetScale: 2,
+ value: '500000'
+ }
+ }
+ }
+ ]
+ },
+ 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
+ }
+ }
+ }
+)
+```
+
+
+
+
+```rust wrap
+use open_payments::types::{
+ AccessTokenRequest,
+ AccessItem,
+ OutgoingPaymentAction,
+ InteractRequest,
+ InteractStart,
+ InteractFinish,
+ InteractFinishMethod,
+ AccessLimits,
+ Amount,
+ GrantRequest,
+};
+
+let outgoing_access = AccessTokenRequest {
+access: vec![AccessItem::OutgoingPayment {
+identifier: Some(sender_wallet_address.id.clone()),
+actions: vec![OutgoingPaymentAction::Create],
+limits: Some(AccessLimits {
+receive_amount: Some(Amount { value: "500000".into(), asset_code: "MXN".into(), asset_scale: 2 }),
+..Default::default()
+}),
+}],
+};
+let interact = InteractRequest {
+start: Some(vec![InteractStart::Redirect]),
+finish: Some(InteractFinish {
+method: InteractFinishMethod::Redirect,
+uri: Some("https://myapp.example.com/finish/{...}".into()),
+nonce: Some("NONCE".into()),
+}),
+};
+let outgoing_grant_request = GrantRequest::new(outgoing_access, Some(interact));
+let pending_sender_outgoing_payment_grant = client
+.grant()
+.request(&sender_wallet_address.auth_server, &outgoing_grant_request)
+.await?;
+
+```
+
+
+
+
+
+```php wrap
+$pendingSenderOutgoingPaymentGrant = $client->grant()->request(
+ [
+ 'url' => $senderWalletAddress->authServer
+ ],
+ [
+ 'access_token' => [
+ 'access' => [
+ [
+ 'identifier' => $senderWalletAddress->id,
+ 'type' => 'outgoing-payment',
+ 'actions' => ['create'],
+ 'limits' => [
+ 'receiveAmount' => [
+ 'assetCode' => 'MXN',
+ 'assetScale' => 2,
+ 'value' => '500000'
+ ]
+ ]
+ ]
+ ]
+ ],
+ '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'
+ ]
+ ]
+ ]
+);
+```
+
+
+
+
+
+```go wrap
+outgoingAccess := as.AccessOutgoing{
+ Type: as.OutgoingPayment,
+ Actions: []as.AccessOutgoingActions{as.AccessOutgoingActionsCreate},
+ Identifier: *senderWalletAddress.Id,
+ Limits: &as.LimitsOutgoing{
+ ReceiveAmount: &as.Amount{
+ Value: "500000",
+ AssetCode: "MXN",
+ AssetScale: 2,
+ },
+ },
+}
+outgoingAccessItem := as.AccessItem{}
+if err := outgoingAccessItem.FromAccessOutgoing(outgoingAccess); err != nil {
+ log.Fatalf("Error creating AccessItem: %v\n", err)
+}
+outgoingAccessToken := struct {
+ Access as.Access `json:"access"`
+}{
+ Access: []as.AccessItem{outgoingAccessItem},
+}
+interact := &as.InteractRequest{
+ Start: []as.InteractRequestStart{as.InteractRequestStartRedirect},
+ Finish: &as.InteractRequestFinish{
+ Method: as.Redirect,
+ Uri: "https://myapp.example.com/finish/{...}",
+ Nonce: NONCE,
+ },
+}
+
+pendingSenderOutgoingPaymentGrant, err := client.Grant.Request(context.TODO(), op.GrantRequestParams{
+ URL: *senderWalletAddress.AuthServer,
+ RequestBody: as.GrantRequestWithAccessToken{
+ AccessToken: outgoingAccessToken,
+ Interact: interact,
+ },
+})
+if err != nil {
+ log.Fatalf("Error requesting outgoing payment grant: %v\n", err)
+}
+```
+
+
+
+
+```java wrap
+ var urlToOpen = "https://myapp.example.com/finish/{...}";
+
+var opContinueInteract = client.auth().grant().continuation(
+senderWalletAddress,
+senderQuote.getDebitAmount(),
+URI.create(urlToOpen),
+"NONCE"
+);
+
+```
+
+
+
+
+
+```csharp wrap
+var pendingSenderOutgoingPaymentGrant = await client.RequestGrantAsync(
+ new RequestArgs
+ {
+ Url = senderWalletAddress.AuthServer,
+ },
+ new GrantCreateBodyWithInteract
+ {
+ AccessToken = new AccessToken
+ {
+ Access =
+ [
+ new OutgoingAccess
+ {
+ Identifier = senderWalletAddress.Id,
+ Actions = [Actions.Create],
+ Limits = new OutgoingAccessLimits
+ {
+ ReceiveAmount = new AuthAmount("500000", "MXN", 2)
+ }
+ }
+ ]
+ },
+ Interact = new InteractRequest
+ {
+ Start = [Start.Redirect],
+ Finish = new Finish
+ {
+ Method = FinishMethod.Redirect,
+ Uri = new Uri("https://localhost"), // where to redirect your user after they've completed the interaction
+ Nonce = NONCE
+ }
+ }
+ }
+);
+```
+
+
+
+
diff --git a/docs/src/content/docs/partials/code/guides/onetime-remittance-fixed-receive/_grant-request-quote.mdx b/docs/src/content/docs/partials/code/guides/onetime-remittance-fixed-receive/_grant-request-quote.mdx
new file mode 100644
index 00000000..3dbfc9d5
--- /dev/null
+++ b/docs/src/content/docs/partials/code/guides/onetime-remittance-fixed-receive/_grant-request-quote.mdx
@@ -0,0 +1,131 @@
+import { Tabs, TabItem } from '@astrojs/starlight/components'
+
+
+
+
+```ts wrap
+const senderQuoteGrant = await client.grant.request(
+ {
+ url: senderWalletAddress.authServer
+ },
+ {
+ access_token: {
+ access: [
+ {
+ type: 'quote',
+ actions: ['create']
+ }
+ ]
+ }
+ }
+)
+```
+
+
+
+
+```rust wrap
+use open_payments::types::{
+ AccessTokenRequest,
+ AccessItem,
+ QuoteAction,
+ GrantRequest,
+};
+
+let quote_access = AccessTokenRequest {
+access: vec![AccessItem::Quote { actions: vec![QuoteAction::Create] }],
+};
+let quote_grant_request = GrantRequest::new(quote_access, None);
+let sender_quote_grant = client
+.grant()
+.request(&sender_wallet_address.auth_server, "e_grant_request)
+.await?;
+
+```
+
+
+
+
+
+```php wrap
+$senderQuoteGrant = $client->grant()->request(
+ [
+ 'url' => $senderWalletAddress->authServer
+ ],
+ [
+ 'access_token' => [
+ 'access' => [
+ [
+ 'type' => 'quote',
+ 'actions' => ['create']
+ ]
+ ]
+ ]
+ ]
+);
+```
+
+
+
+
+
+```go wrap
+quoteAccess := as.AccessQuote{
+ Type: as.Quote,
+ Actions: []as.AccessQuoteActions{as.Create},
+}
+quoteAccessItem := as.AccessItem{}
+if err := quoteAccessItem.FromAccessQuote(quoteAccess); err != nil {
+ log.Fatalf("Error creating AccessItem: %v\n", err)
+}
+quoteAccessToken := struct {
+ Access as.Access `json:"access"`
+}{
+ Access: []as.AccessItem{quoteAccessItem},
+}
+
+senderQuoteGrant, err := client.Grant.Request(context.TODO(), op.GrantRequestParams{
+ URL: senderWalletAddress.AuthServer,
+ RequestBody: as.GrantRequestWithAccessToken{AccessToken: quoteAccessToken},
+})
+if err != nil {
+ log.Fatalf("Error requesting quote grant: %v\n", err)
+}
+```
+
+
+
+
+```java wrap
+var senderQuoteGrant = client.auth().grant().quote(senderWalletAddress);
+```
+
+
+
+
+
+```csharp wrap
+var senderQuoteGrant = await client.RequestGrantAsync(
+ new RequestArgs
+ {
+ Url = senderWalletAddress.AuthServer,
+ },
+ new GrantCreateBody
+ {
+ AccessToken = new AccessToken
+ {
+ Access =
+ [
+ new QuoteAccess
+ {
+ Actions = [Actions.Create]
+ }
+ ]
+ }
+ }
+);
+```
+
+
+
+
diff --git a/docs/src/content/docs/partials/code/guides/onetime-remittance-fixed-receive/_request-a-grant-continuation.mdx b/docs/src/content/docs/partials/code/guides/onetime-remittance-fixed-receive/_request-a-grant-continuation.mdx
new file mode 100644
index 00000000..d3421d07
--- /dev/null
+++ b/docs/src/content/docs/partials/code/guides/onetime-remittance-fixed-receive/_request-a-grant-continuation.mdx
@@ -0,0 +1,100 @@
+import { Tabs, TabItem } from '@astrojs/starlight/components'
+
+
+
+
+```ts wrap
+const senderOutgoingPaymentGrant = await client.grant.continue(
+ {
+ url: pendingSenderOutgoingPaymentGrant.continue.uri,
+ accessToken: pendingSenderOutgoingPaymentGrant.continue.access_token.value
+ },
+ {
+ interact_ref: interactRef
+ }
+)
+```
+
+
+
+
+```rust wrap
+let continue_field = match &pending_sender_outgoing_payment_grant.continue_field {
+ Some(c) => c,
+ None => {
+ eprintln!("Missing continue field on pending grant");
+ return Ok(());
+ }
+};
+let sender_outgoing_payment_grant = client
+ .grant()
+ .continue_grant(
+ &continue_field.uri,
+ &interact_ref,
+ Some(&continue_field.access_token.value),
+ )
+ .await?;
+```
+
+
+
+
+
+```php wrap
+$senderOutgoingPaymentGrant = $client->grant()->continue(
+ [
+ 'url' => $pendingSenderOutgoingPaymentGrant->continue->uri,
+ 'accessToken' => $pendingSenderOutgoingPaymentGrant->continue->access_token->value
+ ],
+ [
+ 'interact_ref' => $interactRef
+ ]
+);
+```
+
+
+
+
+
+```go wrap
+senderOutgoingPaymentGrant, err := client.Grant.Continue(context.TODO(), op.GrantContinueParams{
+ URL: pendingSenderOutgoingPaymentGrant.Continue.Uri,
+ AccessToken: pendingSenderOutgoingPaymentGrant.Continue.AccessToken.Value,
+ InteractRef: INTERACT_REF,
+})
+if err != nil {
+ log.Fatalf("Error continuing grant: %v\n", err)
+}
+```
+
+
+
+
+```java wrap
+var senderOutgoingPaymentGrant = client.auth().grant().finalize(
+ opContinueInteract,
+ interactRef
+);
+```
+
+
+
+
+
+```csharp wrap
+var senderOutgoingPaymentGrant = await client.ContinueGrantAsync(
+ new AuthRequestArgs
+ {
+ Url = pendingSenderOutgoingPaymentGrant.Continue.Uri,
+ AccessToken = pendingSenderOutgoingPaymentGrant.Continue.AccessToken.Value
+ },
+ new GrantContinueBody
+ {
+ InteractRef = interactRef
+ }
+);
+```
+
+
+
+
diff --git a/docs/src/content/docs/partials/code/guides/outgoing-grant-future-payments/_get-wallet-address.mdx b/docs/src/content/docs/partials/code/guides/outgoing-grant-future-payments/_get-wallet-address.mdx
new file mode 100644
index 00000000..f7b300e1
--- /dev/null
+++ b/docs/src/content/docs/partials/code/guides/outgoing-grant-future-payments/_get-wallet-address.mdx
@@ -0,0 +1,60 @@
+import { Tabs, TabItem } from '@astrojs/starlight/components'
+
+
+
+
+```ts
+const userWalletAddress = await client.walletAddress.get({
+ url: 'https://cloudninebank.example.com/user'
+})
+```
+
+
+
+
+```rust wrap
+let user_wallet_address = client.wallet_address().get("https://cloudninebank.example.com/user").await?;
+```
+
+
+
+
+
+```php wrap
+$userWalletAddress = $client->walletAddress()->get([
+ 'url' => 'https://cloudninebank.example.com/user'
+]);
+```
+
+
+
+
+
+```go wrap
+userWalletAddress, err := client.WalletAddress.Get(context.TODO(), op.WalletAddressGetParams{
+ URL: "https://cloudninebank.example.com/user",
+})
+if err != nil {
+ log.Fatalf("Error fetching user wallet address: %v\n", err)
+}
+```
+
+
+
+
+
+```java wrap
+var userWalletAddress = client.walletAddress().get("https://cloudninebank.example.com/user");
+```
+
+
+
+
+
+```csharp wrap
+var userWalletAddress = await client.GetWalletAddressAsync("https://cloudninebank.example.com/user");
+```
+
+
+
+
diff --git a/docs/src/content/docs/partials/code/guides/outgoing-grant-future-payments/_grant-request-outgoing-payment.mdx b/docs/src/content/docs/partials/code/guides/outgoing-grant-future-payments/_grant-request-outgoing-payment.mdx
new file mode 100644
index 00000000..89ba9410
--- /dev/null
+++ b/docs/src/content/docs/partials/code/guides/outgoing-grant-future-payments/_grant-request-outgoing-payment.mdx
@@ -0,0 +1,231 @@
+import { Tabs, TabItem } from '@astrojs/starlight/components'
+
+
+
+
+```ts
+const grant = await client.grant.request(
+ {
+ url: userWalletAddress.authServer,
+ },
+ {
+ access_token: {
+ access: [
+ {
+ identifier: userWalletAddress.id,
+ type: 'outgoing-payment',
+ actions: ['read', 'create'],
+ limits: {
+ interval: 'R3/2025-05-20T13:00:00Z/P1M'
+ debitAmount: {
+ assetCode: 'CAD',
+ assetScale: 2,
+ value: '10000',
+ },
+ },
+ },
+ ],
+ },
+ client: userWalletAddress.id,
+ interact: {
+ start: ['redirect'],
+ finish: {
+ method: 'redirect',
+ uri: 'https://paymentplatform.example/finish/{...}', // where to redirect the user to after they've completed the interaction
+ nonce: NONCE,
+ },
+ },
+ },
+);
+```
+
+
+
+
+```rust wrap
+use open_payments::types::{AccessTokenRequest, AccessItem, OutgoingPaymentAction, AccessLimits, Amount, InteractRequest, InteractStart, InteractFinish, InteractFinishMethod, GrantRequest};
+let outgoing_access = AccessTokenRequest {
+ access: vec![AccessItem::OutgoingPayment {
+ identifier: Some(user_wallet_address.id.clone()),
+ actions: vec![OutgoingPaymentAction::Create, OutgoingPaymentAction::Read],
+ limits: Some(AccessLimits {
+ interval: Some("R3/2025-05-20T13:00:00Z/P1M".into()),
+ debit_amount: Some(Amount { value: "10000".into(), asset_code: "CAD".into(), asset_scale: 2 }),
+ ..Default::default()
+ }),
+ }],
+};
+let interact = InteractRequest { start: Some(vec![InteractStart::Redirect]), finish: Some(InteractFinish { method: InteractFinishMethod::Redirect, uri: Some("https://paymentplatform.example/finish/{...}".into()), nonce: Some("NONCE".into()) }) };
+let outgoing_grant_request = GrantRequest::new(outgoing_access, Some(interact));
+let pending_user_outgoing_payment_grant = client
+ .grant()
+ .request(&user_wallet_address.auth_server, &outgoing_grant_request)
+ .await?;
+```
+
+
+
+
+```php wrap
+$grant = $client->grant()->request(
+ [
+ 'url' => $userWalletAddress->authServer,
+ ],
+ [
+ 'access_token' => [
+ 'access' => [
+ [
+ 'identifier' => $userWalletAddress->id,
+ 'type' => 'outgoing-payment',
+ 'actions' => ['read', 'create'],
+ 'limits' => [
+ 'interval' => 'R3/2025-05-20T13:00:00Z/P1M',
+ 'debitAmount' => [
+ 'assetCode' => 'CAD',
+ 'assetScale' => 2,
+ 'value' => '10000',
+ ],
+ ],
+ ],
+ ],
+ ],
+ 'client' => $userWalletAddress->id,
+ 'interact' => [
+ 'start' => ['redirect'],
+ 'finish' => [
+ 'method' => 'redirect',
+ 'uri' => 'https://paymentplatform.example/finish/{...}', // where to redirect the user to after they've completed the interaction
+ 'nonce' => NONCE,
+ ],
+ ],
+ ],
+);
+```
+
+
+
+
+```go wrap
+interval := "R3/2025-05-20T13:00:00Z/P1M"
+limits := as.LimitsOutgoing{}
+if err := limits.FromLimitsOutgoing1(as.LimitsOutgoing1{
+ Interval: &interval,
+ DebitAmount: as.Amount{
+ Value: "10000",
+ AssetCode: "CAD",
+ AssetScale: 2,
+ },
+}); err != nil {
+ log.Fatalf("Error creating limits: %v\n", err)
+}
+
+outgoingAccess := as.AccessOutgoing{
+ Type: as.OutgoingPayment,
+ Actions: []as.AccessOutgoingActions{as.AccessOutgoingActionsCreate, as.AccessOutgoingActionsRead},
+ Identifier: *userWalletAddress.Id,
+ Limits: &limits,
+}
+outgoingAccessItem := as.AccessItem{}
+if err := outgoingAccessItem.FromAccessOutgoing(outgoingAccess); err != nil {
+ log.Fatalf("Error creating AccessItem: %v\n", err)
+}
+outgoingAccessToken := struct {
+ Access as.Access `json:"access"`
+}{
+ Access: []as.AccessItem{outgoingAccessItem},
+}
+interact := &as.InteractRequest{
+ Start: []as.InteractRequestStart{as.InteractRequestStartRedirect},
+ Finish: &as.InteractRequestFinish{
+ Method: as.Redirect,
+ Uri: "https://paymentplatform.example/finish/{...}",
+ Nonce: NONCE,
+ },
+}
+
+pendingUserOutgoingPaymentGrant, err := client.Grant.Request(context.TODO(), op.GrantRequestParams{
+ URL: *userWalletAddress.AuthServer,
+ RequestBody: as.GrantRequestWithAccessToken{
+ AccessToken: outgoingAccessToken,
+ Interact: interact,
+ },
+})
+if err != nil {
+ log.Fatalf("Error requesting outgoing payment grant: %v\n", err)
+}
+```
+
+
+
+
+
+```java wrap
+var interval = "R3/2025-05-20T13:00:00Z/P1M";
+
+var limits = LimitsOutgoing.build(
+ interval,
+ Amount.build(BigDecimal.valueOf(100.00), "CAD", 2)
+);
+
+var accessRequest = AccessTokenRequest.build(
+ userWalletAddress.getId(),
+ limits
+);
+
+var urlToOpen = "https://paymentplatform.example/finish/{...}";
+
+var grantRequest = client.auth().grant().request(
+ userWalletAddress,
+ accessRequest,
+ URI.create(urlToOpen),
+ "NONCE"
+);
+```
+
+
+
+
+
+```csharp wrap
+var grant = await client.RequestGrantAsync(
+ new RequestArgs
+ {
+ Url = userWalletAddress.AuthServer,
+ },
+ new GrantCreateBodyWithInteract
+ {
+ AccessToken = new AccessToken
+ {
+ Access =
+ [
+ new OutgoingAccess
+ {
+ Identifier = userWalletAddress.Id,
+ Actions = [Actions.Create, Actions.Read],
+ Limits = new OutgoingAccessLimits
+ {
+ DebitAmount = new AuthAmount("10000", "CAD", 2),
+ Interval = "R3/2025-05-20T13:00:00Z/P1M"
+ }
+ }
+ ]
+ },
+ Client = userWalletAddress.Id,
+ Interact = new InteractRequest
+ {
+ Start = [Start.Redirect],
+ Finish = new Finish
+ {
+ Method = FinishMethod.Redirect,
+ Uri = new Uri(
+ "https://localhost"), // where to redirect your user after they've completed the interaction
+ Nonce = NONCE
+ }
+ }
+ }
+);
+```
+
+
+
+
diff --git a/docs/src/content/docs/partials/code/guides/outgoing-grant-future-payments/_request-a-grant-continuation.mdx b/docs/src/content/docs/partials/code/guides/outgoing-grant-future-payments/_request-a-grant-continuation.mdx
new file mode 100644
index 00000000..849d14f7
--- /dev/null
+++ b/docs/src/content/docs/partials/code/guides/outgoing-grant-future-payments/_request-a-grant-continuation.mdx
@@ -0,0 +1,101 @@
+import { Tabs, TabItem } from '@astrojs/starlight/components'
+
+
+
+
+```ts wrap
+const userOutgoingPaymentGrant = await client.grant.continue(
+ {
+ accessToken: pendingUserOutgoingPaymentGrant.continue.acces_token.value,
+ url: pendingUserOutgoingPaymentGrant.continue.uri
+ },
+ {
+ interact_ref: interactRef
+ }
+)
+```
+
+
+
+
+```rust wrap
+let continue_field = match &pending_user_outgoing_payment_grant.continue_field {
+ Some(c) => c,
+ None => {
+ eprintln!("Missing continue field on pending grant");
+ return Ok(());
+ }
+};
+let user_outgoing_payment_grant = client
+ .grant()
+ .continue_grant(
+ &continue_field.uri,
+ &interact_ref,
+ Some(&continue_field.access_token.value),
+ )
+ .await?;
+```
+
+
+
+
+
+```php wrap
+$userOutgoingPaymentGrant = $client->grant()->continue(
+ [
+ 'accessToken' => $pendingUserOutgoingPaymentGrant->continue->access_token->value,
+ 'url' => $pendingUserOutgoingPaymentGrant->continue->uri,
+ ],
+ [
+ 'interact_ref' => $interactRef,
+ ],
+);
+```
+
+
+
+
+
+```go wrap
+userOutgoingPaymentGrant, err := client.Grant.Continue(context.TODO(), op.GrantContinueParams{
+ URL: pendingUserOutgoingPaymentGrant.Continue.Uri,
+ AccessToken: pendingUserOutgoingPaymentGrant.Continue.AccessToken.Value,
+ InteractRef: INTERACT_REF,
+})
+if err != nil {
+ log.Fatalf("Error continuing grant: %v\n", err)
+}
+```
+
+
+
+
+
+```java wrap
+var userOutgoingPaymentGrant = client.auth().grant().finalize(
+ grantRequest,
+ interactRef
+);
+```
+
+
+
+
+
+```csharp wrap
+var userOutgoingPaymentGrant = await client.ContinueGrantAsync(
+ new AuthRequestArgs
+ {
+ Url = grant.Continue.Uri,
+ AccessToken = grant.Continue.AccessToken.Value
+ },
+ new GrantContinueBody()
+ {
+ InteractRef = interactRef
+ }
+);
+```
+
+
+
+
diff --git a/docs/src/content/docs/partials/code/guides/recurring-remittance-fixed-debit/_create-incoming-payment-open.mdx b/docs/src/content/docs/partials/code/guides/recurring-remittance-fixed-debit/_create-incoming-payment-open.mdx
new file mode 100644
index 00000000..f47774ff
--- /dev/null
+++ b/docs/src/content/docs/partials/code/guides/recurring-remittance-fixed-debit/_create-incoming-payment-open.mdx
@@ -0,0 +1,103 @@
+import { Tabs, TabItem } from '@astrojs/starlight/components'
+
+
+
+
+```ts wrap
+const recipientIncomingPayment = await client.incomingPayment.create(
+ {
+ url: recipientWalletAddress.resourceServer,
+ accessToken: recipientIncomingPaymentGrant.access_token.value
+ },
+ {
+ walletAddress: recipientWalletAddress.id
+ }
+)
+```
+
+
+
+
+```rust wrap
+use open_payments::types::IncomingPaymentRequest;
+let incoming_request = IncomingPaymentRequest {
+ wallet_address: recipient_wallet_address.id.clone(),
+ incoming_amount: None,
+ expires_at: None,
+ metadata: None,
+};
+let recipient_incoming_payment = client
+ .incoming_payments()
+ .create(
+ &recipient_wallet_address.resource_server,
+ &incoming_request,
+ Some(&recipient_incoming_payment_grant.access_token.value),
+ )
+ .await?;
+```
+
+
+
+
+
+```php wrap
+$recipientIncomingPayment = $client->incomingPayment()->create(
+ [
+ 'url' => $recipientWalletAddress->resourceServer,
+ 'accessToken' => $recipientIncomingPaymentGrant->access_token->value
+ ],
+ [
+ 'walletAddress' => $recipientWalletAddress->id
+ ]
+);
+```
+
+
+
+
+
+```go wrap
+recipientIncomingPayment, err := client.IncomingPayment.Create(context.TODO(), op.IncomingPaymentCreateParams{
+ BaseURL: *recipientWalletAddress.ResourceServer,
+ AccessToken: recipientIncomingPaymentGrant.AccessToken.Value,
+ Payload: rs.CreateIncomingPaymentJSONBody{
+ WalletAddressSchema: *recipientWalletAddress.Id,
+ },
+})
+if err != nil {
+ log.Fatalf("Error creating incoming payment: %v\n", err)
+}
+```
+
+
+
+
+
+```java wrap
+var recipientIncomingPayment = client.payment().createIncoming(
+ recipientWalletAddress,
+ recipientIncomingPaymentGrant
+);
+```
+
+
+
+
+
+```csharp wrap
+var recipientIncomingPayment = await client.CreateIncomingPaymentAsync(
+ new AuthRequestArgs
+ {
+ Url = recipientWalletAddress.ResourceServer,
+ AccessToken = recipientIncomingPaymentGrant.AccessToken.Value
+ },
+ new IncomingPaymentBody
+ {
+ WalletAddress = recipientWalletAddress.Id
+ }
+);
+```
+
+
+
+
diff --git a/docs/src/content/docs/partials/code/guides/recurring-remittance-fixed-debit/_create-outgoing-payment.mdx b/docs/src/content/docs/partials/code/guides/recurring-remittance-fixed-debit/_create-outgoing-payment.mdx
new file mode 100644
index 00000000..82a95222
--- /dev/null
+++ b/docs/src/content/docs/partials/code/guides/recurring-remittance-fixed-debit/_create-outgoing-payment.mdx
@@ -0,0 +1,133 @@
+import { Tabs, TabItem } from '@astrojs/starlight/components'
+
+
+
+
+```ts wrap
+const senderOutgoingPayment = await client.outgoingPayment.create(
+ {
+ url: senderWalletAddress.resourceServer,
+ accessToken: senderOutgoingPaymentGrant.access_token.value
+ },
+ {
+ walletAddress: senderWalletAddress.id,
+ incomingPayment: recipientIncomingPayment.id,
+ debitAmount: {
+ assetCode: 'USD',
+ assetScale: 2,
+ value: '20000'
+ }
+ }
+)
+```
+
+
+
+
+```rust wrap
+use open_payments::types::{OutgoingPaymentRequest, Amount};
+let outgoing_request = OutgoingPaymentRequest::FromIncomingPayment {
+ wallet_address: sender_wallet_address.id.clone(),
+ incoming_payment_id: recipient_incoming_payment.id.clone(),
+ debit_amount: Amount {
+ value: "20000".into(),
+ asset_code: "USD".into(),
+ asset_scale: 2,
+ },
+ metadata: None,
+};
+let sender_outgoing_payment = client
+ .outgoing_payments()
+ .create(
+ &sender_wallet_address.resource_server,
+ &outgoing_request,
+ Some(&sender_outgoing_payment_grant.access_token.value),
+ )
+ .await?;
+```
+
+
+
+
+
+```php wrap
+$senderOutgoingPayment = $client->outgoingPayment()->create(
+ [
+ 'url' => $senderWalletAddress->resourceServer,
+ 'accessToken' => $senderOutgoingPaymentGrant->access_token->value
+ ],
+ [
+ 'walletAddress' => $senderWalletAddress->id,
+ 'incomingPayment' => $recipientIncomingPayment->id,
+ 'debitAmount' => [
+ 'assetCode' => 'USD',
+ 'assetScale' => 2,
+ 'value' => '20000'
+ ],
+ ]
+ );
+```
+
+
+
+
+
+```go wrap
+var outgoingPayload rs.CreateOutgoingPaymentRequest
+if err := outgoingPayload.FromCreateOutgoingPaymentWithoutQuote(rs.CreateOutgoingPaymentWithoutQuote{
+ WalletAddressSchema: *senderWalletAddress.Id,
+ IncomingPayment: *recipientIncomingPayment.Id,
+ DebitAmount: &rs.Amount{
+ Value: "20000",
+ AssetCode: "USD",
+ AssetScale: 2,
+ },
+}); err != nil {
+ log.Fatalf("Error creating payload: %v\n", err)
+}
+
+senderOutgoingPayment, err := client.OutgoingPayment.Create(context.TODO(), op.OutgoingPaymentCreateParams{
+ BaseURL: *senderWalletAddress.ResourceServer,
+ AccessToken: senderOutgoingPaymentGrant.AccessToken.Value,
+ Payload: outgoingPayload,
+})
+if err != nil {
+ log.Fatalf("Error creating outgoing payment: %v\n", err)
+}
+```
+
+
+
+
+
+```java wrap
+var senderOutgoingPayment = client.payment().createOutgoingFromIncoming(
+ senderWalletAddress,
+ recipientIncomingPayment,
+ senderOutgoingPaymentGrant
+);
+```
+
+
+
+
+
+```csharp wrap
+var senderOutgoingPayment = await client.CreateOutgoingPaymentAsync(
+ new AuthRequestArgs
+ {
+ Url = senderWalletAddress.ResourceServer,
+ AccessToken = senderOutgoingPaymentGrant.AccessToken.Value
+ },
+ new OutgoingPaymentBodyFromIncomingPayment
+ {
+ WalletAddress = senderWalletAddress.Id,
+ IncomingPayment = recipientIncomingPayment.Id,
+ DebitAmount = new Amount("20000", "USD", 2)
+ }
+);
+```
+
+
+
+
diff --git a/docs/src/content/docs/partials/code/guides/recurring-remittance-fixed-debit/_get-wallet-address.mdx b/docs/src/content/docs/partials/code/guides/recurring-remittance-fixed-debit/_get-wallet-address.mdx
new file mode 100644
index 00000000..b78278b0
--- /dev/null
+++ b/docs/src/content/docs/partials/code/guides/recurring-remittance-fixed-debit/_get-wallet-address.mdx
@@ -0,0 +1,75 @@
+import { Tabs, TabItem } from '@astrojs/starlight/components'
+
+
+
+
+```ts wrap
+const senderWalletAddress = await client.walletAddress.get({
+ url: 'https://cloudninebank.example.com/sender'
+})
+const recipientWalletAddress = await client.walletAddress.get({
+ url: 'https://happylifebank.example.com/recipient'
+})
+```
+
+
+
+
+```rust wrap
+let sender_wallet_address = client.wallet_address().get("https://cloudninebank.example.com/sender").await?;
+let recipient_wallet_address = client.wallet_address().get("https://happylifebank.example.com/recipient").await?;
+```
+
+
+
+
+```php wrap
+$senderWalletAddress = $client->walletAddress()->get([
+ 'url' => 'https://cloudninebank.example.com/sender'
+]);
+$recipientWalletAddress = $client->walletAddress()->get([
+ 'url' => 'https://happylifebank.example.com/recipient'
+]);
+```
+
+
+
+
+
+```go wrap
+senderWalletAddress, err := client.WalletAddress.Get(context.TODO(), op.WalletAddressGetParams{
+ URL: "https://cloudninebank.example.com/sender",
+})
+if err != nil {
+ log.Fatalf("Error fetching sender wallet address: %v\n", err)
+}
+
+recipientWalletAddress, err := client.WalletAddress.Get(context.TODO(), op.WalletAddressGetParams{
+ URL: "https://happylifebank.example.com/recipient",
+})
+if err != nil {
+ log.Fatalf("Error fetching recipient wallet address: %v\n", err)
+}
+```
+
+
+
+
+
+```java wrap
+var senderWalletAddress = client.walletAddress().get("https://cloudninebank.example.com/sender");
+var recipientWalletAddress = client.walletAddress().get("https://happylifebank.example.com/recipient");
+```
+
+
+
+
+
+```csharp wrap
+var senderWalletAddress = await client.GetWalletAddressAsync("https://cloudninebank.example.com/sender");
+var recipientWalletAddress = await client.GetWalletAddressAsync("https://happylifebank.example.com/recipient");
+```
+
+
+
+
diff --git a/docs/src/content/docs/partials/code/guides/recurring-remittance-fixed-debit/_grant-request-incoming-payment.mdx b/docs/src/content/docs/partials/code/guides/recurring-remittance-fixed-debit/_grant-request-incoming-payment.mdx
new file mode 100644
index 00000000..2d42e832
--- /dev/null
+++ b/docs/src/content/docs/partials/code/guides/recurring-remittance-fixed-debit/_grant-request-incoming-payment.mdx
@@ -0,0 +1,125 @@
+import { Tabs, TabItem } from '@astrojs/starlight/components'
+
+
+
+
+```ts wrap
+const recipientIncomingPaymentGrant = await client.grant.request(
+ {
+ url: recipientWalletAddress.authServer
+ },
+ {
+ access_token: {
+ access: [
+ {
+ type: 'incoming-payment',
+ actions: ['create']
+ }
+ ]
+ }
+ }
+)
+```
+
+
+
+
+```rust wrap
+use open_payments::types::{AccessTokenRequest, AccessItem, IncomingPaymentAction, GrantRequest};
+let incoming_access = AccessTokenRequest {
+ access: vec![AccessItem::IncomingPayment { actions: vec![IncomingPaymentAction::Create], identifier: None }],
+};
+let incoming_grant_request = GrantRequest::new(incoming_access, None);
+let recipient_incoming_payment_grant = client
+ .grant()
+ .request(&recipient_wallet_address.auth_server, &incoming_grant_request)
+ .await?;
+```
+
+
+
+
+
+```php wrap
+$recipientIncomingPaymentGrant = $client->grant()->request(
+ [
+ 'url' => $recipientWalletAddress->authServer
+ ],
+ [
+ 'access_token' => [
+ 'access' => [
+ [
+ 'type' => 'incoming-payment',
+ 'actions' => ['create'],
+ ],
+ ],
+ ],
+ ]
+);
+```
+
+
+
+
+
+```go
+incomingAccess := as.AccessIncoming{
+ Type: as.IncomingPayment,
+ Actions: []as.AccessIncomingActions{as.AccessIncomingActionsCreate},
+}
+accessItem := as.AccessItem{}
+if err := accessItem.FromAccessIncoming(incomingAccess); err != nil {
+ log.Fatalf("Error creating AccessItem: %v\n", err)
+}
+accessToken := struct {
+ Access as.Access `json:"access"`
+}{
+ Access: []as.AccessItem{accessItem},
+}
+
+recipientIncomingPaymentGrant, err := client.Grant.Request(context.TODO(), op.GrantRequestParams{
+ URL: *recipientWalletAddress.AuthServer,
+ RequestBody: as.GrantRequestWithAccessToken{AccessToken: accessToken},
+})
+if err != nil {
+ log.Fatalf("Error requesting incoming payment grant: %v\n", err)
+}
+```
+
+
+
+
+
+```java wrap
+var recipientIncomingPaymentGrant = client.auth().grant().incomingPayment(recipientWalletAddress);
+```
+
+
+
+
+
+```csharp wrap
+var recipientIncomingPaymentGrant = await client.RequestGrantAsync(
+ new RequestArgs
+ {
+ Url = recipientWalletAddress.AuthServer,
+ },
+ new GrantCreateBody
+ {
+ AccessToken = new AccessToken
+ {
+ Access =
+ [
+ new IncomingAccess
+ {
+ Actions = [Actions.Create]
+ }
+ ]
+ }
+ }
+);
+```
+
+
+
+
diff --git a/docs/src/content/docs/partials/code/guides/recurring-remittance-fixed-debit/_grant-request-outgoing-payment.mdx b/docs/src/content/docs/partials/code/guides/recurring-remittance-fixed-debit/_grant-request-outgoing-payment.mdx
new file mode 100644
index 00000000..a5dad322
--- /dev/null
+++ b/docs/src/content/docs/partials/code/guides/recurring-remittance-fixed-debit/_grant-request-outgoing-payment.mdx
@@ -0,0 +1,241 @@
+import { Tabs, TabItem } from '@astrojs/starlight/components'
+
+
+
+
+```ts wrap
+const pendingSenderOutgoingPaymentGrant = await client.grant.request(
+ {
+ url: senderWalletAddress.authServer
+ },
+ {
+ access_token: {
+ access: [
+ {
+ identifier: senderWalletAddress.id,
+ type: 'outgoing-payment',
+ actions: ['create'],
+ limits: {
+ interval: 'R3/2025-10-03T23:25:00Z/P1M',
+ debitAmount: {
+ assetCode: 'USD',
+ assetScale: 2,
+ value: '20000' // $200.00 USD per interval
+ }
+ }
+ }
+ ]
+ },
+ 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
+ }
+ }
+ }
+)
+```
+
+
+
+
+```rust wrap
+use open_payments::types::{
+ AccessTokenRequest,
+ AccessItem,
+ OutgoingPaymentAction,
+ LimitsOutgoing,
+ Amount,
+ Interval,
+ InteractRequest,
+ InteractFinish,
+ GrantRequest,
+};
+use uuid::Uuid;
+
+let outgoing_access = AccessTokenRequest {
+access: vec![AccessItem::OutgoingPayment {
+identifier: sender_wallet_address.id.clone(),
+actions: vec![OutgoingPaymentAction::Create],
+limits: Some(LimitsOutgoing {
+receiver: None,
+debit_amount: Some(Amount {
+value: "20000".into(),
+asset_code: "USD".into(),
+asset_scale: 2,
+}),
+receive_amount: None,
+interval: Some(Interval("R3/2025-10-03T23:25:00Z/P1M".to_string())),
+}),
+}],
+};
+
+let interact = InteractRequest {
+start: vec!["redirect".to_string()],
+finish: Some(InteractFinish {
+method: "redirect".to_string(),
+uri: "https://myapp.example.com/finish/{...}".to_string(),
+nonce: Uuid::new_v4().to_string(),
+}),
+};
+
+let outgoing_grant_request = GrantRequest::new(outgoing_access, Some(interact));
+
+let pending_sender_outgoing_payment_grant = client
+.grant()
+.request(&sender_wallet_address.auth_server, &outgoing_grant_request)
+.await?;
+
+```
+
+
+
+
+
+```php wrap
+$pendingSenderOutgoingPaymentGrant = $client->grant()->request(
+ [
+ 'url' => $senderWalletAddress->authServer
+ ],
+ [
+ 'access_token' => [
+ 'access' => [
+ [
+ 'identifier' => $senderWalletAddress->id,
+ 'type' => 'outgoing-payment',
+ 'actions' => ['create'],
+ 'limits' => [
+ 'interval' => 'R3/2025-10-03T23:25:00Z/P1M',
+ 'debitAmount' => [
+ 'assetCode' => 'USD',
+ 'assetScale' => 2,
+ 'value' => '20000', // $200.00 USD per interval
+ ]
+ ]
+ ]
+ ]
+ ],
+ '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
+ ]
+ ]
+ ]
+);
+```
+
+
+
+
+
+```go wrap
+interval := "R3/2025-10-03T23:25:00Z/P1M"
+limits := as.LimitsOutgoing{}
+if err := limits.FromLimitsOutgoing1(as.LimitsOutgoing1{
+ Interval: &interval,
+ DebitAmount: as.Amount{
+ Value: "20000", // $200.00 USD per interval
+ AssetCode: "USD",
+ AssetScale: 2,
+ },
+}); err != nil {
+ log.Fatalf("Error creating limits: %v\n", err)
+}
+
+outgoingAccess := as.AccessOutgoing{
+ Type: as.OutgoingPayment,
+ Actions: []as.AccessOutgoingActions{as.AccessOutgoingActionsCreate},
+ Identifier: *senderWalletAddress.Id,
+ Limits: &limits,
+}
+outgoingAccessItem := as.AccessItem{}
+if err := outgoingAccessItem.FromAccessOutgoing(outgoingAccess); err != nil {
+ log.Fatalf("Error creating AccessItem: %v\n", err)
+}
+outgoingAccessToken := struct {
+ Access as.Access `json:"access"`
+}{
+ Access: []as.AccessItem{outgoingAccessItem},
+}
+interact := &as.InteractRequest{
+ Start: []as.InteractRequestStart{as.InteractRequestStartRedirect},
+ Finish: &as.InteractRequestFinish{
+ Method: as.Redirect,
+ Uri: "https://myapp.example.com/finish/{...}", // where to redirect your user after they've completed the interaction
+ Nonce: NONCE,
+ },
+}
+
+pendingSenderOutgoingPaymentGrant, err := client.Grant.Request(context.TODO(), op.GrantRequestParams{
+ URL: *senderWalletAddress.AuthServer,
+ RequestBody: as.GrantRequestWithAccessToken{
+ AccessToken: outgoingAccessToken,
+ Interact: interact,
+ },
+})
+if err != nil {
+ log.Fatalf("Error requesting outgoing payment grant: %v\n", err)
+}
+```
+
+
+
+
+
+```java wrap
+// Build an outgoing payment grant with a fixed debit amount and interval using the Java SDK types.
+// See the Java SDK docs for constructing a LimitsOutgoing object with debitAmount and interval.
+var pendingSenderOutgoingPaymentGrant = client.auth().grant().outgoingPayment(senderWalletAddress);
+```
+
+
+
+
+
+```csharp wrap
+var pendingSenderOutgoingPaymentGrant = await client.RequestGrantAsync(
+ new RequestArgs
+ {
+ Url = senderWalletAddress.AuthServer,
+ },
+ new GrantCreateBodyWithInteract
+ {
+ AccessToken = new AccessToken
+ {
+ Access =
+ [
+ new OutgoingAccess
+ {
+ Identifier = senderWalletAddress.Id,
+ Actions = [Actions.Create],
+ Limits = new OutgoingAccessLimits
+ {
+ DebitAmount = new AuthAmount("20000", "USD", 2),
+ Interval = "R3/2025-10-03T23:25:00Z/P1M"
+ }
+ }
+ ]
+ },
+ Interact = new InteractRequest
+ {
+ Start = [Start.Redirect],
+ Finish = new Finish
+ {
+ Method = FinishMethod.Redirect,
+ Uri = new Uri(
+ "https://localhost"), // where to redirect your user after they've completed the interaction
+ Nonce = NONCE
+ }
+ }
+ }
+);
+```
+
+
+
+
diff --git a/docs/src/content/docs/partials/code/guides/recurring-remittance-fixed-debit/_request-a-grant-continuation.mdx b/docs/src/content/docs/partials/code/guides/recurring-remittance-fixed-debit/_request-a-grant-continuation.mdx
new file mode 100644
index 00000000..dabcd7e1
--- /dev/null
+++ b/docs/src/content/docs/partials/code/guides/recurring-remittance-fixed-debit/_request-a-grant-continuation.mdx
@@ -0,0 +1,103 @@
+import { Tabs, TabItem } from '@astrojs/starlight/components'
+
+
+
+
+```ts wrap
+const senderOutgoingPaymentGrant = await client.grant.continue(
+ {
+ url: pendingSenderOutgoingPaymentGrant.continue.uri,
+ accessToken: pendingSenderOutgoingPaymentGrant.continue.access_token.value
+ },
+ {
+ interact_ref: interactRef
+ }
+)
+```
+
+
+
+
+```rust wrap
+use open_payments::types::GrantResponse;
+let (continue_uri, continue_token) = match &pending_sender_outgoing_payment_grant {
+ GrantResponse::WithInteraction { continue_, .. } | GrantResponse::WithToken { continue_, .. } => {
+ (&continue_.uri, &continue_.access_token.value)
+ }
+};
+let sender_outgoing_payment_grant = client
+ .grant()
+ .continue_grant(
+ continue_uri,
+ &interact_ref,
+ Some(continue_token),
+ )
+ .await?;
+```
+
+
+
+
+
+```php wrap
+$senderOutgoingPaymentGrant = $client->grant()->continue(
+ [
+ 'url' => $pendingSenderOutgoingPaymentGrant->continue->uri,
+ 'accessToken' => $pendingSenderOutgoingPaymentGrant->continue->access_token->value
+ ],
+ [
+ 'interact_ref' => $interactRef
+ ]
+);
+```
+
+
+
+
+
+```go wrap
+senderOutgoingPaymentGrant, err := client.Grant.Continue(context.TODO(), op.GrantContinueParams{
+ URL: pendingSenderOutgoingPaymentGrant.Continue.Uri,
+ AccessToken: pendingSenderOutgoingPaymentGrant.Continue.AccessToken.Value,
+ InteractRef: INTERACT_REF,
+})
+if err != nil {
+ log.Fatalf("Error continuing grant: %v\n", err)
+}
+```
+
+
+
+
+
+```java wrap
+var senderOutgoingPaymentGrant = client.grant().continueRequest(
+ GrantContinueOptions.builder()
+ .url(pendingSenderOutgoingPaymentGrant.getContinue().getUri())
+ .accessToken(pendingSenderOutgoingPaymentGrant.getContinue().getAccessToken().getValue())
+ .interactRef(interactRef)
+ .build()
+);
+```
+
+
+
+
+
+```csharp wrap
+var senderOutgoingPaymentGrant = await client.ContinueGrantAsync(
+ new AuthRequestArgs
+ {
+ Url = pendingSenderOutgoingPaymentGrant.Continue.Uri,
+ AccessToken = pendingSenderOutgoingPaymentGrant.Continue.AccessToken.Value
+ },
+ new GrantContinueBody
+ {
+ InteractRef = interactRef
+ }
+);
+```
+
+
+
+
diff --git a/docs/src/content/docs/partials/code/guides/recurring-remittance-fixed-receive/_create-incoming-payment.mdx b/docs/src/content/docs/partials/code/guides/recurring-remittance-fixed-receive/_create-incoming-payment.mdx
new file mode 100644
index 00000000..b546703d
--- /dev/null
+++ b/docs/src/content/docs/partials/code/guides/recurring-remittance-fixed-receive/_create-incoming-payment.mdx
@@ -0,0 +1,103 @@
+import { Tabs, TabItem } from '@astrojs/starlight/components'
+
+
+
+
+```ts wrap
+const recipientIncomingPayment = await client.incomingPayment.create(
+ {
+ url: recipientWalletAddress.resourceServer,
+ accessToken: recipientIncomingPaymentGrant.access_token.value
+ },
+ {
+ walletAddress: recipientWalletAddress.id
+ }
+)
+```
+
+
+
+
+```rust wrap
+use open_payments::types::IncomingPaymentRequest;
+let incoming_request = IncomingPaymentRequest {
+ wallet_address: recipient_wallet_address.id.clone(),
+ incoming_amount: None,
+ expires_at: None,
+ metadata: None,
+};
+let recipient_incoming_payment = client
+ .incoming_payments()
+ .create(
+ &recipient_wallet_address.resource_server,
+ &incoming_request,
+ Some(&recipient_incoming_payment_grant.access_token.value),
+ )
+ .await?;
+```
+
+
+
+
+
+```php wrap
+$recipientIncomingPayment = $client->incomingPayment()->create(
+ [
+ 'url' => $recipientWalletAddress->resourceServer,
+ 'accessToken' => $recipientIncomingPaymentGrant->access_token->value
+ ],
+ [
+ 'walletAddress' => $recipientWalletAddress->id,
+ ]
+);
+```
+
+
+
+
+
+```go wrap
+recipientIncomingPayment, err := client.IncomingPayment.Create(context.TODO(), op.IncomingPaymentCreateParams{
+ BaseURL: *recipientWalletAddress.ResourceServer,
+ AccessToken: recipientIncomingPaymentGrant.AccessToken.Value,
+ Payload: rs.CreateIncomingPaymentJSONBody{
+ WalletAddressSchema: *recipientWalletAddress.Id,
+ },
+})
+if err != nil {
+ log.Fatalf("Error creating incoming payment: %v\n", err)
+}
+```
+
+
+
+
+
+```java wrap
+var recipientIncomingPayment = client.payment().createIncoming(
+ recipientWalletAddress,
+ recipientIncomingPaymentGrant
+);
+```
+
+
+
+
+
+```csharp wrap
+var recipientIncomingPayment = await client.CreateIncomingPaymentAsync(
+ new AuthRequestArgs
+ {
+ Url = recipientWalletAddress.ResourceServer,
+ AccessToken = recipientIncomingPaymentGrant.AccessToken.Value
+ },
+ new IncomingPaymentBody
+ {
+ WalletAddress = recipientWalletAddress.Id
+ }
+);
+```
+
+
+
+
diff --git a/docs/src/content/docs/partials/code/guides/recurring-remittance-fixed-receive/_create-outgoing-payment.mdx b/docs/src/content/docs/partials/code/guides/recurring-remittance-fixed-receive/_create-outgoing-payment.mdx
new file mode 100644
index 00000000..ff6e60d4
--- /dev/null
+++ b/docs/src/content/docs/partials/code/guides/recurring-remittance-fixed-receive/_create-outgoing-payment.mdx
@@ -0,0 +1,111 @@
+import { Tabs, TabItem } from '@astrojs/starlight/components'
+
+
+
+
+```ts wrap
+const senderOutgoingPayment = await client.outgoingPayment.create(
+ {
+ url: senderWalletAddress.resourceServer,
+ accessToken: senderOutgoingPaymentGrant.access_token.value
+ },
+ {
+ walletAddress: senderWalletAddress.id,
+ quoteId: senderQuote.id
+ }
+)
+```
+
+
+
+
+```rust wrap
+use open_payments::types::OutgoingPaymentRequest;
+let outgoing_request = OutgoingPaymentRequest::FromQuote {
+ wallet_address: sender_wallet_address.id.clone(),
+ quote_id: sender_quote.id.clone(),
+ metadata: None,
+};
+let sender_outgoing_payment = client
+ .outgoing_payments()
+ .create(
+ &sender_wallet_address.resource_server,
+ &outgoing_request,
+ Some(&sender_outgoing_payment_grant.access_token.value),
+ )
+ .await?;
+```
+
+
+
+
+```php wrap
+$senderOutgoingPayment = $client->outgoingPayment()->create(
+ [
+ 'url' => $senderWalletAddress->resourceServer,
+ 'accessToken' => $senderOutgoingPaymentGrant->access_token->value
+ ],
+ [
+ 'walletAddress' => $senderWalletAddress->id,
+ 'quoteId' => $senderQuote->id,
+ ]
+);
+```
+
+
+
+
+
+```go wrap
+var outgoingPayload rs.CreateOutgoingPaymentRequest
+if err := outgoingPayload.FromCreateOutgoingPaymentWithQuote(rs.CreateOutgoingPaymentWithQuote{
+ WalletAddressSchema: *senderWalletAddress.Id,
+ QuoteId: *senderQuote.Id,
+}); err != nil {
+ log.Fatalf("Error creating payload: %v\n", err)
+}
+
+senderOutgoingPayment, err := client.OutgoingPayment.Create(context.TODO(), op.OutgoingPaymentCreateParams{
+ BaseURL: *senderWalletAddress.ResourceServer,
+ AccessToken: senderOutgoingPaymentGrant.AccessToken.Value,
+ Payload: outgoingPayload,
+})
+if err != nil {
+ log.Fatalf("Error creating outgoing payment: %v\n", err)
+}
+```
+
+
+
+
+
+```java wrap
+var senderOutgoingPayment = client.payment().createOutgoingFromQuote(
+ senderWalletAddress,
+ senderQuote,
+ senderOutgoingPaymentGrant
+);
+```
+
+
+
+
+
+```csharp wrap
+var senderOutgoingPayment = await client.CreateOutgoingPaymentAsync(
+ new AuthRequestArgs
+ {
+ Url = senderWalletAddress.ResourceServer,
+ AccessToken = senderOutgoingPaymentGrant.AccessToken.Value
+ },
+ new OutgoingPaymentBodyFromQuote
+ {
+ WalletAddress = senderWalletAddress.Id,
+ QuoteId = senderQuote.Id,
+ }
+);
+```
+
+
+
+
diff --git a/docs/src/content/docs/partials/code/guides/recurring-remittance-fixed-receive/_create-quote-ilp.mdx b/docs/src/content/docs/partials/code/guides/recurring-remittance-fixed-receive/_create-quote-ilp.mdx
new file mode 100644
index 00000000..a63bc7cf
--- /dev/null
+++ b/docs/src/content/docs/partials/code/guides/recurring-remittance-fixed-receive/_create-quote-ilp.mdx
@@ -0,0 +1,134 @@
+import { Tabs, TabItem } from '@astrojs/starlight/components'
+
+
+
+
+```ts wrap
+const senderQuote = await client.quote.create(
+ {
+ url: senderWalletAddress.resourceServer,
+ accessToken: senderQuoteGrant.access_token.value
+ },
+ {
+ method: 'ilp',
+ walletAddress: senderWalletAddress.id,
+ receiver: recipientIncomingPayment.id,
+ receiveAmount: {
+ value: '400000',
+ assetCode: 'MXN',
+ assetScale: 2
+ }
+ }
+)
+```
+
+
+
+
+```rust wrap
+use open_payments::types::{CreateQuoteRequest, PaymentMethodType, Receiver, Amount};
+let quote_request = CreateQuoteRequest::FixedReceiveAmountQuote {
+ wallet_address: sender_wallet_address.id.clone(),
+ receiver: Receiver(recipient_incoming_payment.id.clone()),
+ method: PaymentMethodType::Ilp,
+ receive_amount: Amount {
+ value: "400000".into(),
+ asset_code: "MXN".into(),
+ asset_scale: 2,
+ },
+};
+let sender_quote = client
+ .quotes()
+ .create(
+ &sender_wallet_address.resource_server,
+ "e_request,
+ Some(&sender_quote_grant.access_token.value),
+ )
+ .await?;
+```
+
+
+
+
+
+```php wrap
+$senderQuote = $client->quote()->create(
+ [
+ 'url' => $senderWalletAddress->resourceServer,
+ 'accessToken' => $senderQuoteGrant->access_token->value
+ ],
+ [
+ 'method' => 'ilp',
+ 'walletAddress' => $senderWalletAddress->id,
+ 'receiver' => $recipientIncomingPayment->id,
+ 'receiveAmount' => [
+ 'value' => '400000',
+ 'assetCode' => 'MXN',
+ 'assetScale' => 2
+ ]
+ ]
+);
+```
+
+
+
+
+
+```go wrap
+senderQuote, err := client.Quote.Create(context.TODO(), op.QuoteCreateParams{
+ BaseURL: *senderWalletAddress.ResourceServer,
+ AccessToken: senderQuoteGrant.AccessToken.Value,
+ Payload: rs.CreateQuoteJSONBody1{
+ WalletAddressSchema: *senderWalletAddress.Id,
+ Receiver: *recipientIncomingPayment.Id,
+ Method: "ilp",
+ ReceiveAmount: rs.Amount{
+ Value: "400000",
+ AssetCode: "MXN",
+ AssetScale: 2,
+ },
+ },
+})
+if err != nil {
+ log.Fatalf("Error creating quote: %v\n", err)
+}
+```
+
+
+
+
+
+```java wrap
+var senderQuote = client.quote().create(
+ senderQuoteGrant.getAccess().getToken(),
+ senderWalletAddress,
+ recipientIncomingPayment,
+ Optional.empty(),
+ Optional.empty()
+);
+```
+
+
+
+
+
+```csharp wrap
+var senderQuote = await client.CreateQuoteAsync(
+ new AuthRequestArgs
+ {
+ Url = senderWalletAddress.ResourceServer,
+ AccessToken = senderQuoteGrant.AccessToken.Value
+ },
+ new QuoteBodyWithReceiveAmount
+ {
+ Method = PaymentMethod.Ilp,
+ WalletAddress = senderWalletAddress.Id,
+ Receiver = recipientIncomingPayment.Id,
+ ReceiveAmount = new Amount("400000", "MXN", 2)
+ }
+);
+```
+
+
+
+
diff --git a/docs/src/content/docs/partials/code/guides/recurring-remittance-fixed-receive/_get-wallet-address.mdx b/docs/src/content/docs/partials/code/guides/recurring-remittance-fixed-receive/_get-wallet-address.mdx
new file mode 100644
index 00000000..ccf68942
--- /dev/null
+++ b/docs/src/content/docs/partials/code/guides/recurring-remittance-fixed-receive/_get-wallet-address.mdx
@@ -0,0 +1,75 @@
+import { Tabs, TabItem } from '@astrojs/starlight/components'
+
+
+
+
+```ts wrap
+const senderWalletAddress = await client.walletAddress.get({
+ url: 'https://cloudninebank.example.com/sender'
+})
+const recipientWalletAddress = await client.walletAddress.get({
+ url: 'https://happylifebank.example.com/recipient'
+})
+```
+
+
+
+
+```rust wrap
+let sender_wallet_address = client.wallet_address().get("https://cloudninebank.example.com/sender").await?;
+let recipient_wallet_address = client.wallet_address().get("https://happylifebank.example.com/recipient").await?;
+```
+
+
+
+
+```php wrap
+$senderWalletAddress = $client->walletAddress()->get([
+ 'url' => 'https://cloudninebank.example.com/sender'
+]);
+$recipientWalletAddress = $client->walletAddress()->get([
+ 'url' => 'https://happylifebank.example.com/recipient'
+]);
+```
+
+
+
+
+
+```go wrap
+senderWalletAddress, err := client.WalletAddress.Get(context.TODO(), op.WalletAddressGetParams{
+ URL: "https://cloudninebank.example.com/sender",
+})
+if err != nil {
+ log.Fatalf("Error fetching sender wallet address: %v\n", err)
+}
+
+recipientWalletAddress, err := client.WalletAddress.Get(context.TODO(), op.WalletAddressGetParams{
+ URL: "https://happylifebank.example.com/recipient",
+})
+if err != nil {
+ log.Fatalf("Error fetching recipient wallet address: %v\n", err)
+}
+```
+
+
+
+
+
+```java wrap
+var senderWalletAddress = client.walletAddress().get("https://cloudninebank.example.com/sender");
+var recipientWalletAddress = client.walletAddress().get("https://happylifebank.example.com/recipient");
+```
+
+
+
+
+
+```csharp wrap
+var senderWalletAddress = await client.GetWalletAddressAsync("https://cloudninebank.example.com/sender");
+var recipientWalletAddress = await client.GetWalletAddressAsync("https://happylifebank.example.com/recipient");
+```
+
+
+
+
diff --git a/docs/src/content/docs/partials/code/guides/recurring-remittance-fixed-receive/_grant-request-incoming-payment.mdx b/docs/src/content/docs/partials/code/guides/recurring-remittance-fixed-receive/_grant-request-incoming-payment.mdx
new file mode 100644
index 00000000..72efca88
--- /dev/null
+++ b/docs/src/content/docs/partials/code/guides/recurring-remittance-fixed-receive/_grant-request-incoming-payment.mdx
@@ -0,0 +1,124 @@
+import { Tabs, TabItem } from '@astrojs/starlight/components'
+
+
+
+
+```ts wrap
+const recipientIncomingPaymentGrant = await client.grant.request(
+ {
+ url: recipientWalletAddress.authServer
+ },
+ {
+ access_token: {
+ access: [
+ {
+ type: 'incoming-payment',
+ actions: ['create']
+ }
+ ]
+ }
+ }
+)
+```
+
+
+
+
+```rust wrap
+use open_payments::types::{AccessTokenRequest, AccessItem, IncomingPaymentAction, GrantRequest};
+let incoming_access = AccessTokenRequest {
+ access: vec![AccessItem::IncomingPayment { actions: vec![IncomingPaymentAction::Create], identifier: None }],
+};
+let incoming_grant_request = GrantRequest::new(incoming_access, None);
+let recipient_incoming_payment_grant = client
+ .grant()
+ .request(&recipient_wallet_address.auth_server, &incoming_grant_request)
+ .await?;
+```
+
+
+
+
+
+```php wrap
+$recipientIncomingPaymentGrant = $client->grant()->request(
+ [
+ 'url' => $recipientWalletAddress->authServer
+ ],
+ [
+ 'access_token' => [
+ 'access' => [
+ [
+ 'type' => 'incoming-payment',
+ 'actions' => ['create'],
+ ],
+ ],
+ ],
+ ]
+);
+```
+
+
+
+
+
+```go wrap
+incomingAccess := as.AccessIncoming{
+ Type: as.IncomingPayment,
+ Actions: []as.AccessIncomingActions{as.AccessIncomingActionsCreate},
+}
+accessItem := as.AccessItem{}
+if err := accessItem.FromAccessIncoming(incomingAccess); err != nil {
+ log.Fatalf("Error creating AccessItem: %v\n", err)
+}
+accessToken := struct {
+ Access as.Access `json:"access"`
+}{
+ Access: []as.AccessItem{accessItem},
+}
+recipientIncomingPaymentGrant, err := client.Grant.Request(context.TODO(), op.GrantRequestParams{
+ URL: *recipientWalletAddress.AuthServer,
+ RequestBody: as.GrantRequestWithAccessToken{AccessToken: accessToken},
+})
+if err != nil {
+ log.Fatalf("Error requesting incoming payment grant: %v\n", err)
+}
+```
+
+
+
+
+
+```java wrap
+var recipientIncomingPaymentGrant = client.auth().grant().incomingPayment(recipientWalletAddress);
+```
+
+
+
+
+
+```csharp wrap
+var recipientIncomingPaymentGrant = await client.RequestGrantAsync(
+ new RequestArgs
+ {
+ Url = recipientWalletAddress.AuthServer,
+ },
+ new GrantCreateBody
+ {
+ AccessToken = new AccessToken
+ {
+ Access =
+ [
+ new IncomingAccess
+ {
+ Actions = [Actions.Create],
+ }
+ ]
+ }
+ }
+);
+```
+
+
+
+
diff --git a/docs/src/content/docs/partials/code/guides/recurring-remittance-fixed-receive/_grant-request-outgoing-payment.mdx b/docs/src/content/docs/partials/code/guides/recurring-remittance-fixed-receive/_grant-request-outgoing-payment.mdx
new file mode 100644
index 00000000..7fcbdd61
--- /dev/null
+++ b/docs/src/content/docs/partials/code/guides/recurring-remittance-fixed-receive/_grant-request-outgoing-payment.mdx
@@ -0,0 +1,241 @@
+import { Tabs, TabItem } from '@astrojs/starlight/components'
+
+
+
+
+```ts wrap
+const pendingSenderOutgoingPaymentGrant = await client.grant.request(
+ {
+ url: senderWalletAddress.authServer
+ },
+ {
+ access_token: {
+ access: [
+ {
+ identifier: senderWalletAddress.id,
+ type: 'outgoing-payment',
+ actions: ['create'],
+ limits: {
+ interval: 'R3/2025-10-03T23:25:00Z/P1M',
+ receiveAmount: {
+ assetCode: 'MXN',
+ assetScale: 2,
+ value: '400000'
+ }
+ }
+ }
+ ]
+ },
+ 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
+ }
+ }
+ }
+)
+```
+
+
+
+
+```rust wrap
+use open_payments::types::{
+ AccessTokenRequest,
+ AccessItem,
+ OutgoingPaymentAction,
+ LimitsOutgoing,
+ Amount,
+ Interval,
+ InteractRequest,
+ InteractFinish,
+ GrantRequest,
+};
+use uuid::Uuid;
+
+let outgoing_access = AccessTokenRequest {
+access: vec![AccessItem::OutgoingPayment {
+identifier: sender_wallet_address.id.clone(),
+actions: vec![OutgoingPaymentAction::Create],
+limits: Some(LimitsOutgoing {
+receiver: None,
+debit_amount: None,
+receive_amount: Some(Amount {
+value: "400000".into(),
+asset_code: "MXN".into(),
+asset_scale: 2,
+}),
+interval: Some(Interval("R3/2025-10-03T23:25:00Z/P1M".to_string())),
+}),
+}],
+};
+
+let interact = InteractRequest {
+start: vec!["redirect".to_string()],
+finish: Some(InteractFinish {
+method: "redirect".to_string(),
+uri: "https://myapp.example.com/finish/{...}".to_string(),
+nonce: Uuid::new_v4().to_string(),
+}),
+};
+
+let outgoing_grant_request = GrantRequest::new(outgoing_access, Some(interact));
+
+let pending_sender_outgoing_payment_grant = client
+.grant()
+.request(&sender_wallet_address.auth_server, &outgoing_grant_request)
+.await?;
+
+```
+
+
+
+
+
+```php wrap
+$pendingSenderOutgoingPaymentGrant = $client->grant()->request(
+ [
+ 'url' => $senderWalletAddress->authServer
+ ],
+ [
+ 'access_token' => [
+ 'access' => [
+ [
+ 'identifier' => $senderWalletAddress->id,
+ 'type' => 'outgoing-payment',
+ 'actions' => ['create'],
+ 'limits' => [
+ 'interval' => 'R3/2025-10-03T23:25:00Z/P1M',
+ 'receiveAmount' => [
+ 'assetCode' => 'MXN',
+ 'assetScale' => 2,
+ 'value' => '400000',
+ ]
+ ]
+ ]
+ ]
+ ],
+ '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
+ ]
+ ]
+ ]
+);
+```
+
+
+
+
+
+```go wrap
+interval := "R3/2025-10-03T23:25:00Z/P1M"
+limits := as.LimitsOutgoing{}
+if err := limits.FromLimitsOutgoing2(as.LimitsOutgoing2{
+ Interval: &interval,
+ ReceiveAmount: as.Amount{
+ Value: "400000",
+ AssetCode: "MXN",
+ AssetScale: 2,
+ },
+}); err != nil {
+ log.Fatalf("Error creating limits: %v\n", err)
+}
+
+outgoingAccess := as.AccessOutgoing{
+ Type: as.OutgoingPayment,
+ Actions: []as.AccessOutgoingActions{as.AccessOutgoingActionsCreate},
+ Identifier: *senderWalletAddress.Id,
+ Limits: &limits,
+}
+outgoingAccessItem := as.AccessItem{}
+if err := outgoingAccessItem.FromAccessOutgoing(outgoingAccess); err != nil {
+ log.Fatalf("Error creating AccessItem: %v\n", err)
+}
+outgoingAccessToken := struct {
+ Access as.Access `json:"access"`
+}{
+ Access: []as.AccessItem{outgoingAccessItem},
+}
+interact := &as.InteractRequest{
+ Start: []as.InteractRequestStart{as.InteractRequestStartRedirect},
+ Finish: &as.InteractRequestFinish{
+ Method: as.Redirect,
+ Uri: "https://myapp.example.com/finish/{...}",
+ Nonce: NONCE,
+ },
+}
+
+pendingSenderOutgoingPaymentGrant, err := client.Grant.Request(context.TODO(), op.GrantRequestParams{
+ URL: *senderWalletAddress.AuthServer,
+ RequestBody: as.GrantRequestWithAccessToken{
+ AccessToken: outgoingAccessToken,
+ Interact: interact,
+ },
+})
+if err != nil {
+ log.Fatalf("Error requesting outgoing payment grant: %v\n", err)
+}
+```
+
+
+
+
+
+```java wrap
+// Create an outgoing payment grant with a fixed receive amount and interval using the Java SDK types.
+// See the Java SDK docs for constructing a LimitsOutgoing object with receiveAmount and interval.
+var pendingSenderOutgoingPaymentGrant = client.auth().grant().outgoingPayment(senderWalletAddress);
+```
+
+
+
+
+
+```csharp wrap
+var pendingSenderOutgoingPaymentGrant = await client.RequestGrantAsync(
+ new RequestArgs
+ {
+ Url = senderWalletAddress.AuthServer,
+ },
+ new GrantCreateBodyWithInteract
+ {
+ AccessToken = new AccessToken
+ {
+ Access =
+ [
+ new OutgoingAccess
+ {
+ Identifier = senderWalletAddress.Id,
+ Actions = [Actions.Create],
+ Limits = new OutgoingAccessLimits
+ {
+ DebitAmount = new AuthAmount("400000", "MXN", 2),
+ Interval = "R3/2025-10-03T23:25:00Z/P1M"
+ }
+ }
+ ]
+ },
+ Interact = new InteractRequest
+ {
+ Start = [Start.Redirect],
+ Finish = new Finish
+ {
+ Method = FinishMethod.Redirect,
+ Uri = new Uri(
+ "https://localhost"), // where to redirect your user after they've completed the interaction
+ Nonce = NONCE
+ }
+ }
+ }
+);
+```
+
+
+
+
diff --git a/docs/src/content/docs/partials/code/guides/recurring-remittance-fixed-receive/_grant-request-quote.mdx b/docs/src/content/docs/partials/code/guides/recurring-remittance-fixed-receive/_grant-request-quote.mdx
new file mode 100644
index 00000000..24b2b645
--- /dev/null
+++ b/docs/src/content/docs/partials/code/guides/recurring-remittance-fixed-receive/_grant-request-quote.mdx
@@ -0,0 +1,124 @@
+import { Tabs, TabItem } from '@astrojs/starlight/components'
+
+
+
+
+```ts wrap
+const senderQuoteGrant = await client.grant.request(
+ {
+ url: senderWalletAddress.authServer
+ },
+ {
+ access_token: {
+ access: [
+ {
+ type: 'quote',
+ actions: ['create']
+ }
+ ]
+ }
+ }
+)
+```
+
+
+
+
+```rust wrap
+use open_payments::types::{AccessTokenRequest, AccessItem, QuoteAction, GrantRequest};
+let quote_access = AccessTokenRequest {
+ access: vec![AccessItem::Quote { actions: vec![QuoteAction::Create] }],
+};
+let quote_grant_request = GrantRequest::new(quote_access, None);
+let sender_quote_grant = client
+ .grant()
+ .request(&sender_wallet_address.auth_server, "e_grant_request)
+ .await?;
+```
+
+
+
+
+
+```php wrap
+$senderQuoteGrant = $client->grant()->request(
+ [
+ 'url' => $senderWalletAddress->authServer
+ ],
+ [
+ 'access_token' => [
+ 'access' => [
+ [
+ 'type' => 'quote',
+ 'actions' => ['create']
+ ]
+ ]
+ ]
+ ]
+);
+```
+
+
+
+
+
+```go wrap
+quoteAccess := as.AccessQuote{
+ Type: as.Quote,
+ Actions: []as.AccessQuoteActions{as.Create},
+}
+quoteAccessItem := as.AccessItem{}
+if err := quoteAccessItem.FromAccessQuote(quoteAccess); err != nil {
+ log.Fatalf("Error creating AccessItem: %v\n", err)
+}
+quoteAccessToken := struct {
+ Access as.Access `json:"access"`
+}{
+ Access: []as.AccessItem{quoteAccessItem},
+}
+senderQuoteGrant, err := client.Grant.Request(context.TODO(), op.GrantRequestParams{
+ URL: senderWalletAddress.AuthServer,
+ RequestBody: as.GrantRequestWithAccessToken{AccessToken: quoteAccessToken},
+})
+if err != nil {
+ log.Fatalf("Error requesting quote grant: %v\n", err)
+}
+```
+
+
+
+
+
+```java wrap
+var senderQuoteGrant = client.auth().grant().quote(senderWalletAddress);
+```
+
+
+
+
+
+```csharp wrap
+var senderQuoteGrant = await client.RequestGrantAsync(
+ new RequestArgs
+ {
+ Url = senderWalletAddress.AuthServer,
+ },
+ new GrantCreateBody
+ {
+ AccessToken = new AccessToken
+ {
+ Access =
+ [
+ new QuoteAccess
+ {
+ Actions = [Actions.Create],
+ }
+ ]
+ }
+ }
+);
+```
+
+
+
+
diff --git a/docs/src/content/docs/partials/code/guides/recurring-remittance-fixed-receive/_request-a-grant-continuation.mdx b/docs/src/content/docs/partials/code/guides/recurring-remittance-fixed-receive/_request-a-grant-continuation.mdx
new file mode 100644
index 00000000..dabcd7e1
--- /dev/null
+++ b/docs/src/content/docs/partials/code/guides/recurring-remittance-fixed-receive/_request-a-grant-continuation.mdx
@@ -0,0 +1,103 @@
+import { Tabs, TabItem } from '@astrojs/starlight/components'
+
+
+
+
+```ts wrap
+const senderOutgoingPaymentGrant = await client.grant.continue(
+ {
+ url: pendingSenderOutgoingPaymentGrant.continue.uri,
+ accessToken: pendingSenderOutgoingPaymentGrant.continue.access_token.value
+ },
+ {
+ interact_ref: interactRef
+ }
+)
+```
+
+
+
+
+```rust wrap
+use open_payments::types::GrantResponse;
+let (continue_uri, continue_token) = match &pending_sender_outgoing_payment_grant {
+ GrantResponse::WithInteraction { continue_, .. } | GrantResponse::WithToken { continue_, .. } => {
+ (&continue_.uri, &continue_.access_token.value)
+ }
+};
+let sender_outgoing_payment_grant = client
+ .grant()
+ .continue_grant(
+ continue_uri,
+ &interact_ref,
+ Some(continue_token),
+ )
+ .await?;
+```
+
+
+
+
+
+```php wrap
+$senderOutgoingPaymentGrant = $client->grant()->continue(
+ [
+ 'url' => $pendingSenderOutgoingPaymentGrant->continue->uri,
+ 'accessToken' => $pendingSenderOutgoingPaymentGrant->continue->access_token->value
+ ],
+ [
+ 'interact_ref' => $interactRef
+ ]
+);
+```
+
+
+
+
+
+```go wrap
+senderOutgoingPaymentGrant, err := client.Grant.Continue(context.TODO(), op.GrantContinueParams{
+ URL: pendingSenderOutgoingPaymentGrant.Continue.Uri,
+ AccessToken: pendingSenderOutgoingPaymentGrant.Continue.AccessToken.Value,
+ InteractRef: INTERACT_REF,
+})
+if err != nil {
+ log.Fatalf("Error continuing grant: %v\n", err)
+}
+```
+
+
+
+
+
+```java wrap
+var senderOutgoingPaymentGrant = client.grant().continueRequest(
+ GrantContinueOptions.builder()
+ .url(pendingSenderOutgoingPaymentGrant.getContinue().getUri())
+ .accessToken(pendingSenderOutgoingPaymentGrant.getContinue().getAccessToken().getValue())
+ .interactRef(interactRef)
+ .build()
+);
+```
+
+
+
+
+
+```csharp wrap
+var senderOutgoingPaymentGrant = await client.ContinueGrantAsync(
+ new AuthRequestArgs
+ {
+ Url = pendingSenderOutgoingPaymentGrant.Continue.Uri,
+ AccessToken = pendingSenderOutgoingPaymentGrant.Continue.AccessToken.Value
+ },
+ new GrantContinueBody
+ {
+ InteractRef = interactRef
+ }
+);
+```
+
+
+
+
diff --git a/docs/src/content/docs/partials/code/guides/recurring-subscription-incoming-amount/_create-incoming-payment.mdx b/docs/src/content/docs/partials/code/guides/recurring-subscription-incoming-amount/_create-incoming-payment.mdx
new file mode 100644
index 00000000..076427f8
--- /dev/null
+++ b/docs/src/content/docs/partials/code/guides/recurring-subscription-incoming-amount/_create-incoming-payment.mdx
@@ -0,0 +1,123 @@
+import { Tabs, TabItem } from '@astrojs/starlight/components'
+
+
+
+
+```ts wrap
+const serviceProviderIncomingPayment = await client.incomingPayment.create(
+ {
+ url: serviceProviderWalletAddress.resourceServer,
+ accessToken: serviceProviderIncomingPaymentGrant.access_token.value
+ },
+ {
+ walletAddress: serviceProviderWalletAddress.id,
+ incomingAmount: {
+ value: '1500', // The amount the service provider expects to receive in the first payment
+ assetCode: 'USD',
+ assetScale: 2
+ }
+ }
+)
+```
+
+
+
+
+```rust wrap
+use open_payments::types::{IncomingPaymentRequest, Amount};
+let incoming_request = IncomingPaymentRequest {
+ wallet_address: service_provider_wallet_address.id.clone(),
+ incoming_amount: Some(Amount {
+ value: "1500".into(),
+ asset_code: "USD".into(),
+ asset_scale: 2,
+ }),
+ expires_at: None,
+ metadata: None,
+};
+let service_provider_incoming_payment = client
+ .incoming_payments()
+ .create(
+ &service_provider_wallet_address.resource_server,
+ &incoming_request,
+ Some(&service_provider_incoming_payment_grant.access_token.value),
+ )
+ .await?;
+```
+
+
+
+
+```php wrap
+$serviceProviderIncomingPayment = $client->incomingPayment()->create(
+ [
+ 'url' => $serviceProviderWalletAddress->resourceServer,
+ 'accessToken' => $serviceProviderIncomingPaymentGrant->access_token->value
+ ],
+ [
+ 'walletAddress' => $serviceProviderWalletAddress->id,
+ 'incomingAmount' => [
+ 'value' => '1500', // The amount the service provider expects to receive in the first payment
+ 'assetCode' => 'USD',
+ 'assetScale' => 2
+ ],
+ ]
+);
+```
+
+
+
+
+
+```go wrap
+serviceProviderIncomingPayment, err := client.IncomingPayment.Create(context.TODO(), op.IncomingPaymentCreateParams{
+ BaseURL: *serviceProviderWalletAddress.ResourceServer,
+ AccessToken: serviceProviderIncomingPaymentGrant.AccessToken.Value,
+ Payload: rs.CreateIncomingPaymentJSONBody{
+ WalletAddressSchema: *serviceProviderWalletAddress.Id,
+ IncomingAmount: &rs.Amount{
+ Value: "1500",
+ AssetCode: "USD",
+ AssetScale: 2,
+ },
+ },
+})
+if err != nil {
+ log.Fatalf("Error creating incoming payment: %v\n", err)
+}
+```
+
+
+
+
+
+```java wrap
+var serviceProviderIncomingPayment = client.payment().createIncoming(
+ serviceProviderWalletAddress,
+ serviceProviderIncomingPaymentGrant,
+ BigDecimal.valueOf(15.00)
+);
+```
+
+
+
+
+
+```csharp wrap
+var serviceProviderIncomingPayment = await client.CreateIncomingPaymentAsync(
+ new AuthRequestArgs
+ {
+ Url = serviceProviderWalletAddress.ResourceServer,
+ AccessToken = serviceProviderIncomingPaymentGrant.AccessToken.Value
+ },
+ new IncomingPaymentBody
+ {
+ WalletAddress = serviceProviderWalletAddress.Id,
+ IncomingAmount = new Amount("1500", "USD", 2)
+ }
+);
+```
+
+
+
+
diff --git a/docs/src/content/docs/partials/code/guides/recurring-subscription-incoming-amount/_create-outgoing-payment.mdx b/docs/src/content/docs/partials/code/guides/recurring-subscription-incoming-amount/_create-outgoing-payment.mdx
new file mode 100644
index 00000000..acaa9a1c
--- /dev/null
+++ b/docs/src/content/docs/partials/code/guides/recurring-subscription-incoming-amount/_create-outgoing-payment.mdx
@@ -0,0 +1,109 @@
+import { Tabs, TabItem } from '@astrojs/starlight/components'
+
+
+
+
+```ts wrap
+const customerOutgoingPayment = await client.outgoingPayment.create(
+ {
+ url: customerWalletAddress.resourceServer,
+ accessToken: customerOutgoingPaymentGrant.access_token.value
+ },
+ {
+ walletAddress: customerWalletAddress.id,
+ quoteId: customerQuote.id
+ }
+)
+```
+
+
+
+
+```rust wrap
+use open_payments::types::OutgoingPaymentRequest;
+let outgoing_request = OutgoingPaymentRequest::FromQuote {
+ wallet_address: customer_wallet_address.id.clone(),
+ quote_id: customer_quote.id.clone(),
+ metadata: None,
+};
+let customer_outgoing_payment = client
+ .outgoing_payments()
+ .create(
+ &customer_wallet_address.resource_server,
+ &outgoing_request,
+ Some(&customer_outgoing_payment_grant.access_token.value),
+ )
+ .await?;
+```
+
+
+
+
+```php wrap
+$customerOutgoingPayment = $client->outgoingPayment()->create(
+ [
+ 'url' => $customerWalletAddress->resourceServer,
+ 'accessToken' => $customerOutgoingPaymentGrant->access_token->value
+ ],
+ [
+ 'walletAddress' => $customerWalletAddress->id,
+ 'quoteId' => $customerQuote->id
+ ]
+);
+```
+
+
+
+
+```go wrap
+var outgoingPayload rs.CreateOutgoingPaymentRequest
+if err := outgoingPayload.FromCreateOutgoingPaymentWithQuote(rs.CreateOutgoingPaymentWithQuote{
+ WalletAddressSchema: *customerWalletAddress.Id,
+ QuoteId: *customerQuote.Id,
+}); err != nil {
+ log.Fatalf("Error creating payload: %v\n", err)
+}
+
+customerOutgoingPayment, err := client.OutgoingPayment.Create(context.TODO(), op.OutgoingPaymentCreateParams{
+ BaseURL: *customerWalletAddress.ResourceServer,
+ AccessToken: customerOutgoingPaymentGrant.AccessToken.Value,
+ Payload: outgoingPayload,
+})
+if err != nil {
+ log.Fatalf("Error creating outgoing payment: %v\n", err)
+}
+```
+
+
+
+
+```java wrap
+var customerOutgoingPayment = client.payment().createOutgoing(
+ customerOutgoingPaymentGrant,
+ customerWalletAddress,
+ customerQuote
+);
+```
+
+
+
+
+
+```csharp wrap
+var customerOutgoingPayment = await client.CreateOutgoingPaymentAsync(
+ new AuthRequestArgs
+ {
+ Url = customerWalletAddress.ResourceServer,
+ AccessToken = customerOutgoingPaymentGrant.AccessToken.Value
+ },
+ new OutgoingPaymentBodyFromQuote
+ {
+ WalletAddress = customerWalletAddress.Id,
+ QuoteId = customerQuote.Id,
+ }
+);
+```
+
+
+
+
diff --git a/docs/src/content/docs/partials/code/guides/recurring-subscription-incoming-amount/_create-quote.mdx b/docs/src/content/docs/partials/code/guides/recurring-subscription-incoming-amount/_create-quote.mdx
new file mode 100644
index 00000000..90cbf2e2
--- /dev/null
+++ b/docs/src/content/docs/partials/code/guides/recurring-subscription-incoming-amount/_create-quote.mdx
@@ -0,0 +1,111 @@
+import { Tabs, TabItem } from '@astrojs/starlight/components'
+
+
+
+
+```ts wrap
+const customerQuote = await client.quote.create(
+ {
+ url: customerWalletAddress.resourceServer,
+ accessToken: customerQuoteGrant.access_token.value
+ },
+ {
+ method: 'ilp',
+ walletAddress: customerWalletAddress.id,
+ receiver: serviceProviderIncomingPayment.id
+ }
+)
+```
+
+
+
+
+```rust wrap
+use open_payments::types::{CreateQuoteRequest, PaymentMethodType, Receiver};
+let quote_request = CreateQuoteRequest::NoAmountQuote {
+ wallet_address: customer_wallet_address.id.clone(),
+ receiver: Receiver(service_provider_incoming_payment.id.clone()),
+ method: PaymentMethodType::Ilp,
+};
+let customer_quote = client
+ .quotes()
+ .create(
+ &customer_wallet_address.resource_server,
+ "e_request,
+ Some(&customer_quote_grant.access_token.value),
+ )
+ .await?;
+```
+
+
+
+
+```php wrap
+$customerQuote = $client->quote()->create(
+ [
+ 'url' => $customerWalletAddress->resourceServer,
+ 'accessToken' => $customerQuoteGrant->access_token->value
+ ],
+ [
+ 'method' => 'ilp',
+ 'walletAddress' => $customerWalletAddress->id,
+ 'receiver' => $serviceProviderIncomingPayment->id,
+ ]
+);
+```
+
+
+
+
+```go wrap
+customerQuote, err := client.Quote.Create(context.TODO(), op.QuoteCreateParams{
+ BaseURL: *customerWalletAddress.ResourceServer,
+ AccessToken: customerQuoteGrant.AccessToken.Value,
+ Payload: rs.CreateQuoteJSONBody0{
+ WalletAddressSchema: *customerWalletAddress.Id,
+ Receiver: *serviceProviderIncomingPayment.Id,
+ Method: "ilp",
+ },
+})
+if err != nil {
+ log.Fatalf("Error creating quote: %v\n", err)
+}
+```
+
+
+
+
+
+```java wrap
+var customerQuote = client.quote().create(
+ customerQuoteGrant.getAccess().getToken(),
+ customerWalletAddress,
+ serviceProviderIncomingPayment,
+ Optional.empty(),
+ Optional.empty()
+);
+```
+
+
+
+
+
+```csharp wrap
+var customerQuote = await client.CreateQuoteAsync(
+ new AuthRequestArgs
+ {
+ Url = customerWalletAddress.ResourceServer,
+ AccessToken = customerQuoteGrant.AccessToken.Value
+ },
+ new QuoteBody
+ {
+ Method = PaymentMethod.Ilp,
+ WalletAddress = customerWalletAddress.Id,
+ Receiver = serviceProviderIncomingPayment.Id,
+ }
+);
+```
+
+
+
+
diff --git a/docs/src/content/docs/partials/code/guides/recurring-subscription-incoming-amount/_get-wallet-address.mdx b/docs/src/content/docs/partials/code/guides/recurring-subscription-incoming-amount/_get-wallet-address.mdx
new file mode 100644
index 00000000..766521fe
--- /dev/null
+++ b/docs/src/content/docs/partials/code/guides/recurring-subscription-incoming-amount/_get-wallet-address.mdx
@@ -0,0 +1,75 @@
+import { Tabs, TabItem } from '@astrojs/starlight/components'
+
+
+
+
+```ts
+const customerWalletAddress = await client.walletAddress.get({
+ url: 'https://cloudninebank.example.com/customer'
+})
+const serviceProviderWalletAddress = await client.walletAddress.get({
+ url: 'https://happylifebank.example.com/service-provider'
+})
+```
+
+
+
+
+```rust wrap
+let customer_wallet_address = client.wallet_address().get("https://cloudninebank.example.com/customer").await?;
+let service_provider_wallet_address = client.wallet_address().get("https://happylifebank.example.com/service-provider").await?;
+```
+
+
+
+
+```php wrap
+$customerWalletAddress = $client->walletAddress()->get([
+ 'url' => 'https://cloudninebank.example.com/customer'
+]);
+$serviceProviderWalletAddress = $client->walletAddress()->get([
+ 'url' => 'https://happylifebank.example.com/service-provider'
+]);
+```
+
+
+
+
+
+```go wrap
+customerWalletAddress, err := client.WalletAddress.Get(context.TODO(), op.WalletAddressGetParams{
+ URL: "https://cloudninebank.example.com/customer",
+})
+if err != nil {
+ log.Fatalf("Error fetching customer wallet address: %v\n", err)
+}
+
+serviceProviderWalletAddress, err := client.WalletAddress.Get(context.TODO(), op.WalletAddressGetParams{
+ URL: "https://happylifebank.example.com/service-provider",
+})
+if err != nil {
+ log.Fatalf("Error fetching service provider wallet address: %v\n", err)
+}
+```
+
+
+
+
+
+```java wrap
+var customerWalletAddress = client.walletAddress().get("https://cloudninebank.example.com/customer");
+var serviceProviderWalletAddress = client.walletAddress().get("https://happylifebank.example.com/service-provider");
+```
+
+
+
+
+
+```csharp wrap
+var customerWalletAddress = await client.GetWalletAddressAsync("https://cloudninebank.example.com/customer");
+var serviceProviderWalletAddress = await client.GetWalletAddressAsync("https://happylifebank.example.com/service-provider");
+```
+
+
+
+
diff --git a/docs/src/content/docs/partials/code/guides/recurring-subscription-incoming-amount/_grant-request-incoming-payment.mdx b/docs/src/content/docs/partials/code/guides/recurring-subscription-incoming-amount/_grant-request-incoming-payment.mdx
new file mode 100644
index 00000000..d62713d1
--- /dev/null
+++ b/docs/src/content/docs/partials/code/guides/recurring-subscription-incoming-amount/_grant-request-incoming-payment.mdx
@@ -0,0 +1,124 @@
+import { Tabs, TabItem } from '@astrojs/starlight/components'
+
+
+
+
+```ts wrap
+const serviceProviderIncomingPaymentGrant = await client.grant.request(
+ {
+ url: serviceProviderWalletAddress.authServer
+ },
+ {
+ access_token: {
+ access: [
+ {
+ type: 'incoming-payment',
+ actions: ['create']
+ }
+ ]
+ }
+ }
+)
+```
+
+
+
+
+```rust wrap
+use open_payments::types::{AccessTokenRequest, AccessItem, IncomingPaymentAction, GrantRequest};
+let incoming_access = AccessTokenRequest {
+ access: vec![AccessItem::IncomingPayment { actions: vec![IncomingPaymentAction::Create], identifier: None }],
+};
+let incoming_grant_request = GrantRequest::new(incoming_access, None);
+let service_provider_incoming_payment_grant = client
+ .grant()
+ .request(&service_provider_wallet_address.auth_server, &incoming_grant_request)
+ .await?;
+```
+
+
+
+
+```php wrap
+$serviceProviderIncomingPaymentGrant = $client->grant()->request(
+ [
+ 'url' => $serviceProviderWalletAddress->authServer
+ ],
+ [
+ 'access_token' => [
+ 'access' => [
+ [
+ 'type' => 'incoming-payment',
+ 'actions' => ['create']
+ ]
+ ]
+ ]
+ ]
+);
+```
+
+
+
+
+```go wrap
+incomingAccess := as.AccessIncoming{
+ Type: as.IncomingPayment,
+ Actions: []as.AccessIncomingActions{as.AccessIncomingActionsCreate},
+}
+accessItem := as.AccessItem{}
+if err := accessItem.FromAccessIncoming(incomingAccess); err != nil {
+ log.Fatalf("Error creating AccessItem: %v\n", err)
+}
+accessToken := struct {
+ Access as.Access `json:"access"`
+}{
+ Access: []as.AccessItem{accessItem},
+}
+
+serviceProviderIncomingPaymentGrant, err := client.Grant.Request(context.TODO(), op.GrantRequestParams{
+ URL: *serviceProviderWalletAddress.AuthServer,
+ RequestBody: as.GrantRequestWithAccessToken{AccessToken: accessToken},
+})
+if err != nil {
+ log.Fatalf("Error requesting incoming payment grant: %v\n", err)
+}
+```
+
+
+
+
+```java wrap
+var serviceProviderIncomingPaymentGrant = client.auth().grant().incomingPayment(
+ serviceProviderWalletAddress
+);
+```
+
+
+
+
+
+```csharp wrap
+var serviceProviderIncomingPaymentGrant = await client.RequestGrantAsync(
+ new RequestArgs
+ {
+ Url = serviceProviderWalletAddress.AuthServer,
+ },
+ new GrantCreateBody
+ {
+ AccessToken = new AccessToken
+ {
+ Access =
+ [
+ new IncomingAccess
+ {
+ Actions = [Actions.Create]
+ }
+ ]
+ }
+ }
+);
+```
+
+
+
+
diff --git a/docs/src/content/docs/partials/code/guides/recurring-subscription-incoming-amount/_grant-request-outgoing-payment.mdx b/docs/src/content/docs/partials/code/guides/recurring-subscription-incoming-amount/_grant-request-outgoing-payment.mdx
new file mode 100644
index 00000000..afdfd959
--- /dev/null
+++ b/docs/src/content/docs/partials/code/guides/recurring-subscription-incoming-amount/_grant-request-outgoing-payment.mdx
@@ -0,0 +1,246 @@
+import { Tabs, TabItem } from '@astrojs/starlight/components'
+
+
+
+
+```ts wrap
+const pendingCustomerOutgoingPaymentGrant = await client.grant.request(
+ {
+ url: customerWalletAddress.authServer
+ },
+ {
+ access_token: {
+ access: [
+ {
+ identifier: customerWalletAddress.id,
+ type: 'outgoing-payment',
+ actions: ['create', 'read'],
+ limits: {
+ debitAmount: {
+ assetCode: 'USD',
+ assetScale: 2,
+ value: '1500'
+ },
+ interval: 'R12/2025-10-14T00:03:00Z/P1M'
+ }
+ }
+ ]
+ },
+ interact: {
+ start: ['redirect'],
+ finish: {
+ method: 'redirect',
+ uri: 'https://myapp.example.com/finish/{...}', // where to redirect the customer after they've completed interaction
+ nonce: NONCE
+ }
+ }
+ }
+)
+```
+
+
+
+
+```rust wrap
+use open_payments::types::{
+ AccessTokenRequest,
+ AccessItem,
+ OutgoingPaymentAction,
+ LimitsOutgoing,
+ Amount,
+ Interval,
+ InteractRequest,
+ InteractFinish,
+ GrantRequest,
+};
+use uuid::Uuid;
+
+let outgoing_access = AccessTokenRequest {
+access: vec![AccessItem::OutgoingPayment {
+identifier: customer_wallet_address.id.clone(),
+actions: vec![OutgoingPaymentAction::Create, OutgoingPaymentAction::Read],
+limits: Some(LimitsOutgoing {
+receiver: None,
+debit_amount: Some(Amount {
+value: "1500".into(),
+asset_code: "USD".into(),
+asset_scale: 2,
+}),
+receive_amount: None,
+interval: Some(Interval("R12/2025-10-14T00:03:00Z/P1M".to_string())),
+}),
+}],
+};
+
+let interact = InteractRequest {
+start: vec!["redirect".to_string()],
+finish: Some(InteractFinish {
+method: "redirect".to_string(),
+uri: "https://myapp.example.com/finish/{...}".to_string(),
+nonce: Uuid::new_v4().to_string(),
+}),
+};
+
+let outgoing_grant_request = GrantRequest::new(outgoing_access, Some(interact));
+
+let pending_customer_outgoing_payment_grant = client
+.grant()
+.request(&customer_wallet_address.auth_server, &outgoing_grant_request)
+.await?;
+
+```
+
+
+
+
+
+```php wrap
+$pendingCustomerOutgoingPaymentGrant = $client->grant()->request(
+ [
+ 'url' => $customerWalletAddress->authServer
+ ],
+ [
+ 'access_token' => [
+ 'access' => [
+ [
+ 'identifier' => $customerWalletAddress->id,
+ 'type' => 'outgoing-payment',
+ 'actions' => ['create', 'read'],
+ 'limits' => [
+ 'debitAmount' => [
+ 'assetCode' => 'USD',
+ 'assetScale' => 2,
+ 'value' => '1500',
+ ],
+ 'interval' => 'R12/2025-10-14T00:03:00Z/P1M'
+ ]
+ ]
+ ]
+ ],
+ 'interact' => [
+ 'start' => ['redirect'],
+ 'finish' => [
+ 'method' => 'redirect',
+ 'uri' => 'https://myapp.example.com/finish/{...}', // where to redirect the customer after they've completed interaction
+ 'nonce' => NONCE
+ ]
+ ]
+ ]
+);
+```
+
+
+
+
+
+```go wrap
+interval := "R12/2025-10-14T00:03:00Z/P1M"
+limits := as.LimitsOutgoing{}
+if err := limits.FromLimitsOutgoing1(as.LimitsOutgoing1{
+ Interval: &interval,
+ DebitAmount: as.Amount{
+ Value: "1500",
+ AssetCode: "USD",
+ AssetScale: 2,
+ },
+}); err != nil {
+ log.Fatalf("Error creating limits: %v\n", err)
+}
+
+outgoingAccess := as.AccessOutgoing{
+ Type: as.OutgoingPayment,
+ Actions: []as.AccessOutgoingActions{as.AccessOutgoingActionsCreate, as.AccessOutgoingActionsRead},
+ Identifier: *customerWalletAddress.Id,
+ Limits: &limits,
+}
+outgoingAccessItem := as.AccessItem{}
+if err := outgoingAccessItem.FromAccessOutgoing(outgoingAccess); err != nil {
+ log.Fatalf("Error creating AccessItem: %v\n", err)
+}
+outgoingAccessToken := struct {
+ Access as.Access `json:"access"`
+}{
+ Access: []as.AccessItem{outgoingAccessItem},
+}
+interact := &as.InteractRequest{
+ Start: []as.InteractRequestStart{as.InteractRequestStartRedirect},
+ Finish: &as.InteractRequestFinish{
+ Method: as.Redirect,
+ Uri: "https://myapp.example.com/finish/{...}", // where to redirect the customer after they've completed interaction
+ Nonce: NONCE,
+ },
+}
+
+pendingCustomerOutgoingPaymentGrant, err := client.Grant.Request(context.TODO(), op.GrantRequestParams{
+ URL: *customerWalletAddress.AuthServer,
+ RequestBody: as.GrantRequestWithAccessToken{
+ AccessToken: outgoingAccessToken,
+ Interact: interact,
+ },
+})
+if err != nil {
+ log.Fatalf("Error requesting outgoing payment grant: %v\n", err)
+}
+```
+
+
+
+
+
+```java wrap
+var urlToOpen = "https://myapp.example.com/finish/{...}";
+
+var opContinueInteract = client.auth().grant().continuation(
+ customerWalletAddress,
+ customerQuote.getDebitAmount(),
+ URI.create(urlToOpen),
+ "NONCE"
+);
+```
+
+
+
+
+
+```csharp wrap
+var pendingCustomerOutgoingPaymentGrant = await client.RequestGrantAsync(
+ new RequestArgs
+ {
+ Url = customerWalletAddress.AuthServer,
+ },
+ new GrantCreateBodyWithInteract
+ {
+ AccessToken = new AccessToken
+ {
+ Access =
+ [
+ new OutgoingAccess
+ {
+ Identifier = customerWalletAddress.Id,
+ Actions = [Actions.Create, Actions.Read],
+ Limits = new OutgoingAccessLimits
+ {
+ DebitAmount = new AuthAmount("1500", "USD", 2),
+ Interval = "R12/2025-10-14T00:03:00Z/P1M"
+ }
+ }
+ ]
+ },
+ Interact = new InteractRequest
+ {
+ Start = [Start.Redirect],
+ Finish = new Finish
+ {
+ Method = FinishMethod.Redirect,
+ Uri = new Uri(
+ "https://localhost"), // where to redirect your user after they've completed the interaction
+ Nonce = NONCE
+ }
+ }
+ }
+);
+```
+
+
+
+
diff --git a/docs/src/content/docs/partials/code/guides/recurring-subscription-incoming-amount/_grant-request-quote.mdx b/docs/src/content/docs/partials/code/guides/recurring-subscription-incoming-amount/_grant-request-quote.mdx
new file mode 100644
index 00000000..dcdae1ca
--- /dev/null
+++ b/docs/src/content/docs/partials/code/guides/recurring-subscription-incoming-amount/_grant-request-quote.mdx
@@ -0,0 +1,127 @@
+import { Tabs, TabItem } from '@astrojs/starlight/components'
+
+
+
+
+```ts wrap
+const customerQuoteGrant = await client.grant.request(
+ {
+ url: customerWalletAddress.authServer
+ },
+ {
+ access_token: {
+ access: [
+ {
+ type: 'quote',
+ actions: ['create']
+ }
+ ]
+ }
+ }
+)
+```
+
+
+
+
+```rust wrap
+use open_payments::types::{AccessTokenRequest, AccessItem, QuoteAction, GrantRequest};
+let quote_access = AccessTokenRequest {
+ access: vec![AccessItem::Quote { actions: vec![QuoteAction::Create] }],
+};
+let quote_grant_request = GrantRequest::new(quote_access, None);
+let customer_quote_grant = client
+ .grant()
+ .request(&customer_wallet_address.auth_server, "e_grant_request)
+ .await?;
+```
+
+
+
+
+
+```php wrap
+$customerQuoteGrant = $client->grant()->request(
+ [
+ 'url' => $customerWalletAddress->authServer
+ ],
+ [
+ 'access_token' => [
+ 'access' => [
+ [
+ 'type' => 'quote',
+ 'actions' => ['create']
+ ]
+ ]
+ ]
+ ]
+);
+```
+
+
+
+
+
+```go wrap
+quoteAccess := as.AccessQuote{
+ Type: as.Quote,
+ Actions: []as.AccessQuoteActions{as.Create},
+}
+quoteAccessItem := as.AccessItem{}
+if err := quoteAccessItem.FromAccessQuote(quoteAccess); err != nil {
+ log.Fatalf("Error creating AccessItem: %v\n", err)
+}
+quoteAccessToken := struct {
+ Access as.Access `json:"access"`
+}{
+ Access: []as.AccessItem{quoteAccessItem},
+}
+
+customerQuoteGrant, err := client.Grant.Request(context.TODO(), op.GrantRequestParams{
+ URL: *customerWalletAddress.AuthServer,
+ RequestBody: as.GrantRequestWithAccessToken{AccessToken: quoteAccessToken},
+})
+if err != nil {
+ log.Fatalf("Error requesting quote grant: %v\n", err)
+}
+```
+
+
+
+
+
+```java wrap
+var customerQuoteGrant = client.auth().grant().quote(
+ customerWalletAddress
+);
+```
+
+
+
+
+
+```csharp wrap
+var customerQuoteGrant = await client.RequestGrantAsync(
+ new RequestArgs
+ {
+ Url = customerWalletAddress.AuthServer,
+ },
+ new GrantCreateBody
+ {
+ AccessToken = new AccessToken
+ {
+ Access =
+ [
+ new QuoteAccess
+ {
+ Actions = [Actions.Create]
+ }
+ ]
+ }
+ }
+);
+```
+
+
+
+
diff --git a/docs/src/content/docs/partials/code/guides/recurring-subscription-incoming-amount/_request-a-grant-continuation.mdx b/docs/src/content/docs/partials/code/guides/recurring-subscription-incoming-amount/_request-a-grant-continuation.mdx
new file mode 100644
index 00000000..f2a904e8
--- /dev/null
+++ b/docs/src/content/docs/partials/code/guides/recurring-subscription-incoming-amount/_request-a-grant-continuation.mdx
@@ -0,0 +1,100 @@
+import { Tabs, TabItem } from '@astrojs/starlight/components'
+
+
+
+
+ ```ts wrap
+ const customerOutgoingPaymentGrant = await client.grant.continue(
+ {
+ url: pendingCustomerOutgoingPaymentGrant.continue.uri,
+ accessToken: pendingCustomerOutgoingPaymentGrant.continue.access_token.value
+ },
+ {
+ interact_ref: interactRef
+ }
+ )
+ ```
+
+
+
+
+```rust wrap
+use open_payments::types::GrantResponse;
+let (continue_uri, continue_token) = match &pending_customer_outgoing_payment_grant {
+ GrantResponse::WithInteraction { continue_, .. } | GrantResponse::WithToken { continue_, .. } => {
+ (&continue_.uri, &continue_.access_token.value)
+ }
+};
+let customer_outgoing_payment_grant = client
+ .grant()
+ .continue_grant(
+ continue_uri,
+ &interact_ref,
+ Some(continue_token),
+ )
+ .await?;
+```
+
+
+
+
+
+```php wrap
+$customerOutgoingPaymentGrant = $client->grant()->continue(
+ [
+ 'url' => $pendingCustomerOutgoingPaymentGrant->continue->uri,
+ 'accessToken' => $pendingCustomerOutgoingPaymentGrant->continue->access_token->value
+ ],
+ [
+ 'interact_ref' => $interactRef
+ ]
+);
+```
+
+
+
+
+
+```go wrap
+customerOutgoingPaymentGrant, err := client.Grant.Continue(context.TODO(), op.GrantContinueParams{
+ URL: pendingCustomerOutgoingPaymentGrant.Continue.Uri,
+ AccessToken: pendingCustomerOutgoingPaymentGrant.Continue.AccessToken.Value,
+ InteractRef: INTERACT_REF,
+})
+if err != nil {
+ log.Fatalf("Error continuing grant: %v\n", err)
+}
+```
+
+
+
+
+
+```java wrap
+var customerOutgoingPaymentGrant = client.auth().grant().finalize(
+ opContinueInteract,
+ interactRef
+);
+```
+
+
+
+
+
+```csharp wrap
+var customerOutgoingPaymentGrant = await client.ContinueGrantAsync(
+ new AuthRequestArgs
+ {
+ Url = pendingCustomerOutgoingPaymentGrant.Continue.Uri,
+ AccessToken = pendingCustomerOutgoingPaymentGrant.Continue.AccessToken.Value
+ },
+ new GrantContinueBody
+ {
+ InteractRef = interactRef
+ }
+);
+```
+
+
+
+
diff --git a/docs/src/content/docs/partials/code/guides/split-payments/_create-incoming-payments.mdx b/docs/src/content/docs/partials/code/guides/split-payments/_create-incoming-payments.mdx
new file mode 100644
index 00000000..b9217a6c
--- /dev/null
+++ b/docs/src/content/docs/partials/code/guides/split-payments/_create-incoming-payments.mdx
@@ -0,0 +1,198 @@
+import { Tabs, TabItem } from '@astrojs/starlight/components'
+
+
+
+
+```ts wrap
+// Merchant
+const merchantIncomingPayment = await client.incomingPayment.create(
+ {
+ url: merchantWalletAddress.resourceServer,
+ accessToken: merchantIncomingPaymentGrant.access_token.value
+ },
+ {
+ walletAddress: merchantWalletAddress.id,
+ incomingAmount: {
+ value: '9900',
+ assetCode: 'USD',
+ assetScale: 2
+ }
+ }
+)
+// Platform
+const platformIncomingPayment = await client.incomingPayment.create(
+ {
+ url: platformWalletAddress.resourceServer,
+ accessToken: platformIncomingPaymentGrant.access_token.value
+ },
+ {
+ walletAddress: platformWalletAddress.id,
+ incomingAmount: {
+ value: '100',
+ assetCode: 'USD',
+ assetScale: 2
+ }
+ }
+)
+```
+
+
+
+
+
+```rust wrap
+use open_payments::types::{IncomingPaymentRequest, Amount};
+let merchant_request = IncomingPaymentRequest {
+ wallet_address: merchant_wallet_address.id.clone(),
+ incoming_amount: Some(Amount { value: "9900".into(), asset_code: "USD".into(), asset_scale: 2 }),
+ expires_at: None,
+ metadata: None,
+};
+let platform_request = IncomingPaymentRequest {
+ wallet_address: platform_wallet_address.id.clone(),
+ incoming_amount: Some(Amount { value: "100".into(), asset_code: "USD".into(), asset_scale: 2 }),
+ expires_at: None,
+ metadata: None,
+};
+let merchant_incoming_payment = client
+ .incoming_payments()
+ .create(&merchant_wallet_address.resource_server, &merchant_request, Some(&merchant_incoming_payment_grant.access_token.value))
+ .await?;
+let platform_incoming_payment = client
+ .incoming_payments()
+ .create(&platform_wallet_address.resource_server, &platform_request, Some(&platform_incoming_payment_grant.access_token.value))
+ .await?;
+```
+
+
+
+
+
+```php wrap
+// Merchant
+$merchantIncomingPayment = $client->incomingPayment()->create(
+ [
+ 'url' => $merchantWalletAddress->resourceServer,
+ 'accessToken' => $merchantIncomingPaymentGrant->access_token->value
+ ],
+ [
+ 'walletAddress' => $merchantWalletAddress->id,
+ 'incomingAmount' => [
+ 'value' => '9900',
+ 'assetCode' => 'USD',
+ 'assetScale' => 2
+ ]
+ ]
+);
+// Platform
+$platformIncomingPayment = $client->incomingPayment()->create(
+ [
+ 'url' => $platformWalletAddress->resourceServer,
+ 'accessToken' => $platformIncomingPaymentGrant->access_token->value
+ ],
+ [
+ 'walletAddress' => $platformWalletAddress->id,
+ 'incomingAmount' => [
+ 'value' => '100',
+ 'assetCode' => 'USD',
+ 'assetScale' => 2
+ ]
+ ]
+);
+```
+
+
+
+
+
+```go wrap
+// Merchant
+merchantIncomingPayment, err := client.IncomingPayment.Create(context.TODO(), op.IncomingPaymentCreateParams{
+ BaseURL: *merchantWalletAddress.ResourceServer,
+ AccessToken: merchantIncomingPaymentGrant.AccessToken.Value,
+ Payload: rs.CreateIncomingPaymentJSONBody{
+ WalletAddressSchema: *merchantWalletAddress.Id,
+ IncomingAmount: &rs.Amount{
+ Value: "9900",
+ AssetCode: "USD",
+ AssetScale: 2,
+ },
+ },
+})
+if err != nil {
+ log.Fatalf("Error creating merchant incoming payment: %v\n", err)
+}
+// Platform
+platformIncomingPayment, err := client.IncomingPayment.Create(context.TODO(), op.IncomingPaymentCreateParams{
+ BaseURL: *platformWalletAddress.ResourceServer,
+ AccessToken: platformIncomingPaymentGrant.AccessToken.Value,
+ Payload: rs.CreateIncomingPaymentJSONBody{
+ WalletAddressSchema: *platformWalletAddress.Id,
+ IncomingAmount: &rs.Amount{
+ Value: "100",
+ AssetCode: "USD",
+ AssetScale: 2,
+ },
+ },
+})
+if err != nil {
+ log.Fatalf("Error creating platform incoming payment: %v\n", err)
+}
+```
+
+
+
+
+
+```java wrap
+// Merchant receives 99.00 USD (value 9900, scale 2)
+var merchantIncomingPayment = client.payment().createIncoming(
+ merchantWalletAddress,
+ merchantIncomingPaymentGrant,
+ BigDecimal.valueOf(99.00)
+);
+
+// Platform receives 1.00 USD (value 100, scale 2)
+var platformIncomingPayment = client.payment().createIncoming(
+ platformWalletAddress,
+ platformIncomingPaymentGrant,
+ BigDecimal.valueOf(1.00)
+);
+```
+
+
+
+
+
+```csharp wrap
+// Merchant
+var merchantIncomingPayment = await client.CreateIncomingPaymentAsync(
+ new AuthRequestArgs
+ {
+ Url = merchantWalletAddress.ResourceServer,
+ AccessToken = merchantIncomingPaymentGrant.AccessToken.Value
+ },
+ new IncomingPaymentBody
+ {
+ WalletAddress = merchantWalletAddress.Id,
+ IncomingAmount = new Amount("9900", "USD", 2)
+ }
+);
+// Platform
+var platformIncomingPayment = await client.CreateIncomingPaymentAsync(
+ new AuthRequestArgs
+ {
+ Url = platformWalletAddress.ResourceServer,
+ AccessToken = platformIncomingPaymentGrant.AccessToken.Value
+ },
+ new IncomingPaymentBody
+ {
+ WalletAddress = platformWalletAddress.Id,
+ IncomingAmount = new Amount("100", "USD", 2)
+ }
+);
+```
+
+
+
+
diff --git a/docs/src/content/docs/partials/code/guides/split-payments/_create-outgoing-payments.mdx b/docs/src/content/docs/partials/code/guides/split-payments/_create-outgoing-payments.mdx
new file mode 100644
index 00000000..2dd94525
--- /dev/null
+++ b/docs/src/content/docs/partials/code/guides/split-payments/_create-outgoing-payments.mdx
@@ -0,0 +1,183 @@
+import { Tabs, TabItem } from '@astrojs/starlight/components'
+
+
+
+
+```ts wrap
+// Merchant
+const customerOutgoingPaymentToMerchant = await client.outgoingPayment.create(
+ {
+ url: customerWalletAddress.resourceServer,
+ accessToken: customerOutgoingPaymentGrant.access_token.value
+ },
+ {
+ walletAddress: customerWalletAddress.id,
+ quoteId: merchantQuote.id
+ }
+)
+// Platform
+const customerOutgoingPaymentToPlatform = await client.outgoingPayment.create(
+ {
+ url: customerWalletAddress.resourceServer,
+ accessToken: customerOutgoingPaymentGrant.access_token.value
+ },
+ {
+ walletAddress: customerWalletAddress.id,
+ quoteId: platformQuote.id
+ }
+)
+```
+
+
+
+
+```rust wrap
+use open_payments::types::OutgoingPaymentRequest;
+let merchant_outgoing_request = OutgoingPaymentRequest {
+ wallet_address: customer_wallet_address.id.clone(),
+ receiver: Some(merchant_incoming_payment.id.clone()),
+ debit_amount: None,
+ receive_amount: None,
+ quote_id: Some(merchant_quote.id.clone()),
+};
+let platform_outgoing_request = OutgoingPaymentRequest {
+ wallet_address: customer_wallet_address.id.clone(),
+ receiver: Some(platform_incoming_payment.id.clone()),
+ debit_amount: None,
+ receive_amount: None,
+ quote_id: Some(platform_quote.id.clone()),
+};
+let customer_outgoing_payment_to_merchant = client
+ .outgoing_payments()
+ .create(&customer_wallet_address.resource_server, &merchant_outgoing_request, Some(&customer_outgoing_payment_grant.access_token.value))
+ .await?;
+let customer_outgoing_payment_to_platform = client
+ .outgoing_payments()
+ .create(&customer_wallet_address.resource_server, &platform_outgoing_request, Some(&customer_outgoing_payment_grant.access_token.value))
+ .await?;
+```
+
+
+
+
+
+```php wrap
+// Merchant
+$customerOutgoingPaymentToMerchant = $client->outgoingPayment()->create(
+ [
+ 'url' => $customerWalletAddress->resourceServer,
+ 'accessToken' => $customerOutgoingPaymentGrant->access_token->value
+ ],
+ [
+ 'walletAddress' => $customerWalletAddress->id,
+ 'quoteId' => $merchantQuote->id
+ ]
+);
+// Platform
+$customerOutgoingPaymentToPlatform = $client->outgoingPayment()->create(
+ [
+ 'url' => $customerWalletAddress->resourceServer,
+ 'accessToken' => $customerOutgoingPaymentGrant->access_token->value
+ ],
+ [
+ 'walletAddress' => $customerWalletAddress->id,
+ 'quoteId' => $platformQuote->id
+ ]
+);
+```
+
+
+
+
+
+```go wrap
+// Merchant
+var merchantOutgoingPayload rs.CreateOutgoingPaymentRequest
+if err := merchantOutgoingPayload.FromCreateOutgoingPaymentWithQuote(rs.CreateOutgoingPaymentWithQuote{
+ WalletAddressSchema: *customerWalletAddress.Id,
+ QuoteId: *merchantQuote.Id,
+}); err != nil {
+ log.Fatalf("Error creating merchant payload: %v\n", err)
+}
+customerOutgoingPaymentToMerchant, err := client.OutgoingPayment.Create(context.TODO(), op.OutgoingPaymentCreateParams{
+ BaseURL: *customerWalletAddress.ResourceServer,
+ AccessToken: customerOutgoingPaymentGrant.AccessToken.Value,
+ Payload: merchantOutgoingPayload,
+})
+if err != nil {
+ log.Fatalf("Error creating outgoing payment to merchant: %v\n", err)
+}
+// Platform
+var platformOutgoingPayload rs.CreateOutgoingPaymentRequest
+if err := platformOutgoingPayload.FromCreateOutgoingPaymentWithQuote(rs.CreateOutgoingPaymentWithQuote{
+ WalletAddressSchema: *customerWalletAddress.Id,
+ QuoteId: *platformQuote.Id,
+}); err != nil {
+ log.Fatalf("Error creating platform payload: %v\n", err)
+}
+customerOutgoingPaymentToPlatform, err := client.OutgoingPayment.Create(context.TODO(), op.OutgoingPaymentCreateParams{
+ BaseURL: *customerWalletAddress.ResourceServer,
+ AccessToken: customerOutgoingPaymentGrant.AccessToken.Value,
+ Payload: platformOutgoingPayload,
+})
+if err != nil {
+ log.Fatalf("Error creating outgoing payment to platform: %v\n", err)
+}
+```
+
+
+
+
+
+```java wrap
+// Merchant
+var customerOutgoingPaymentToMerchant = client.payment().createOutgoing(
+ customerOutgoingPaymentGrant,
+ customerWalletAddress,
+ merchantQuote
+);
+
+// Platform
+var customerOutgoingPaymentToPlatform = client.payment().createOutgoing(
+ customerOutgoingPaymentGrant,
+ customerWalletAddress,
+ platformQuote
+);
+```
+
+
+
+
+
+```csharp wrap
+// Merchant
+var customerOutgoingPaymentToMerchant = await client.CreateOutgoingPaymentAsync(
+ new AuthRequestArgs
+ {
+ Url = customerWalletAddress.ResourceServer,
+ AccessToken = customerOutgoingPaymentGrant.AccessToken.Value
+ },
+ new OutgoingPaymentBodyFromQuote
+ {
+ WalletAddress = customerWalletAddress.Id,
+ QuoteId = merchantQuote.Id,
+ }
+);
+// Platform
+var customerOutgoingPaymentToPlatform = await client.CreateOutgoingPaymentAsync(
+ new AuthRequestArgs
+ {
+ Url = customerWalletAddress.ResourceServer,
+ AccessToken = customerOutgoingPaymentGrant.AccessToken.Value
+ },
+ new OutgoingPaymentBodyFromQuote
+ {
+ WalletAddress = customerWalletAddress.Id,
+ QuoteId = platformQuote.Id,
+ }
+);
+```
+
+
+
+
diff --git a/docs/src/content/docs/partials/code/guides/split-payments/_create-quotes.mdx b/docs/src/content/docs/partials/code/guides/split-payments/_create-quotes.mdx
new file mode 100644
index 00000000..6583e20a
--- /dev/null
+++ b/docs/src/content/docs/partials/code/guides/split-payments/_create-quotes.mdx
@@ -0,0 +1,187 @@
+import { Tabs, TabItem } from '@astrojs/starlight/components'
+
+
+
+
+```ts wrap
+// Merchant
+const merchantQuote = await client.quote.create(
+ {
+ url: customerWalletAddress.resourceServer,
+ accessToken: customerQuoteGrant.access_token.value
+ },
+ {
+ method: 'ilp',
+ walletAddress: customerWalletAddress.id,
+ receiver: merchantIncomingPayment.id
+ }
+)
+// Platform
+const platformQuote = await client.quote.create(
+ {
+ url: customerWalletAddress.resourceServer,
+ accessToken: customerQuoteGrant.access_token.value
+ },
+ {
+ method: 'ilp',
+ walletAddress: customerWalletAddress.id,
+ receiver: platformIncomingPayment.id
+ }
+)
+```
+
+
+
+
+```rust wrap
+use open_payments::types::{QuoteRequest, QuoteMethod};
+let merchant_quote_request = QuoteRequest {
+ method: QuoteMethod::Ilp,
+ wallet_address: Some(customer_wallet_address.id.clone()),
+ receiver: Some(merchant_incoming_payment.id.clone()),
+ debit_amount: None,
+ receive_amount: None,
+};
+let platform_quote_request = QuoteRequest {
+ method: QuoteMethod::Ilp,
+ wallet_address: Some(customer_wallet_address.id.clone()),
+ receiver: Some(platform_incoming_payment.id.clone()),
+ debit_amount: None,
+ receive_amount: None,
+};
+let merchant_quote = client
+ .quotes()
+ .create(&customer_wallet_address.resource_server, &merchant_quote_request, Some(&customer_quote_grant.access_token.value))
+ .await?;
+let platform_quote = client
+ .quotes()
+ .create(&customer_wallet_address.resource_server, &platform_quote_request, Some(&customer_quote_grant.access_token.value))
+ .await?;
+```
+
+
+
+
+
+```php wrap
+// Merchant
+$merchantQuote = $client->quote()->create(
+ [
+ 'url' => $customerWalletAddress->resourceServer,
+ 'accessToken' => $customerQuoteGrant->access_token->value
+ ],
+ [
+ 'method' => 'ilp',
+ 'walletAddress' => $customerWalletAddress->id,
+ 'receiver' => $merchantIncomingPayment->id
+ ]
+);
+// Platform
+$platformQuote = $client->quote()->create(
+ [
+ 'url' => $customerWalletAddress->resourceServer,
+ 'accessToken' => $customerQuoteGrant->access_token->value
+ ],
+ [
+ 'method' => 'ilp',
+ 'walletAddress' => $customerWalletAddress->id,
+ 'receiver' => $platformIncomingPayment->id
+ ]
+);
+```
+
+
+
+
+
+```go wrap
+// Merchant
+merchantQuote, err := client.Quote.Create(context.TODO(), op.QuoteCreateParams{
+ BaseURL: *customerWalletAddress.ResourceServer,
+ AccessToken: customerQuoteGrant.AccessToken.Value,
+ Payload: rs.CreateQuoteJSONBody0{
+ WalletAddressSchema: *customerWalletAddress.Id,
+ Receiver: *merchantIncomingPayment.Id,
+ Method: "ilp",
+ },
+})
+if err != nil {
+ log.Fatalf("Error creating merchant quote: %v\n", err)
+}
+// Platform
+platformQuote, err := client.Quote.Create(context.TODO(), op.QuoteCreateParams{
+ BaseURL: *customerWalletAddress.ResourceServer,
+ AccessToken: customerQuoteGrant.AccessToken.Value,
+ Payload: rs.CreateQuoteJSONBody0{
+ WalletAddressSchema: *customerWalletAddress.Id,
+ Receiver: *platformIncomingPayment.Id,
+ Method: "ilp",
+ },
+})
+if err != nil {
+ log.Fatalf("Error creating platform quote: %v\n", err)
+}
+```
+
+
+
+
+
+```java wrap
+// Merchant quote
+var merchantQuote = client.quote().create(
+ customerQuoteGrant.getAccess().getToken(),
+ customerWalletAddress,
+ merchantIncomingPayment,
+ Optional.empty(),
+ Optional.empty()
+);
+
+// Platform quote
+var platformQuote = client.quote().create(
+ customerQuoteGrant.getAccess().getToken(),
+ customerWalletAddress,
+ platformIncomingPayment,
+ Optional.empty(),
+ Optional.empty()
+);
+```
+
+
+
+
+
+```csharp wrap
+// Merchant
+var merchantQuote = await client.CreateQuoteAsync(
+ new AuthRequestArgs
+ {
+ Url = customerWalletAddress.ResourceServer,
+ AccessToken = customerQuoteGrant.AccessToken.Value
+ },
+ new QuoteBody
+ {
+ Method = PaymentMethod.Ilp,
+ WalletAddress = customerWalletAddress.Id,
+ Receiver = merchantIncomingPayment.Id,
+ }
+);
+// Platform
+var platformQuote = await client.CreateQuoteAsync(
+ new AuthRequestArgs
+ {
+ Url = customerWalletAddress.ResourceServer,
+ AccessToken = customerQuoteGrant.AccessToken.Value
+ },
+ new QuoteBody
+ {
+ Method = PaymentMethod.Ilp,
+ WalletAddress = customerWalletAddress.Id,
+ Receiver = platformIncomingPayment.Id,
+ }
+);
+```
+
+
+
+
diff --git a/docs/src/content/docs/partials/code/guides/split-payments/_get-wallet-address.mdx b/docs/src/content/docs/partials/code/guides/split-payments/_get-wallet-address.mdx
new file mode 100644
index 00000000..186384d8
--- /dev/null
+++ b/docs/src/content/docs/partials/code/guides/split-payments/_get-wallet-address.mdx
@@ -0,0 +1,90 @@
+import { Tabs, TabItem } from '@astrojs/starlight/components'
+
+
+
+
+```ts
+const customerWalletAddress = await client.walletAddress.get({
+ url: 'https://cloudninebank.example.com/customer'
+})
+const merchantWalletAddress = await client.walletAddress.get({
+ url: 'https://happylifebank.example.com/merchant'
+})
+const platformWalletAddress = await client.walletAddress.get({
+ url: 'https://coolwallet.example.com/platform'
+})
+```
+
+
+
+
+```rust wrap
+let customer_wallet_address = client.wallet_address().get("https://cloudninebank.example.com/customer").await?;
+let merchant_wallet_address = client.wallet_address().get("https://happylifebank.example.com/merchant").await?;
+let platform_wallet_address = client.wallet_address().get("https://coolwallet.example.com/platform").await?;
+```
+
+
+
+
+
+```php wrap
+$customerWalletAddress = $client->walletAddress()->get([
+ 'url' => 'https://cloudninebank.example.com/customer'
+]);
+$merchantWalletAddress = $client->walletAddress()->get([
+ 'url' => 'https://happylifebank.example.com/merchant'
+]);
+$platformWalletAddress = $client->walletAddress()->get([
+ 'url' => 'https://coolwallet.example.com/platform'
+]);
+```
+
+
+
+
+
+```go wrap
+customerWalletAddress, err := client.WalletAddress.Get(context.TODO(), op.WalletAddressGetParams{
+ URL: "https://cloudninebank.example.com/customer",
+})
+if err != nil {
+ log.Fatalf("Error fetching customer wallet address: %v\n", err)
+}
+merchantWalletAddress, err := client.WalletAddress.Get(context.TODO(), op.WalletAddressGetParams{
+ URL: "https://happylifebank.example.com/merchant",
+})
+if err != nil {
+ log.Fatalf("Error fetching merchant wallet address: %v\n", err)
+}
+platformWalletAddress, err := client.WalletAddress.Get(context.TODO(), op.WalletAddressGetParams{
+ URL: "https://coolwallet.example.com/platform",
+})
+if err != nil {
+ log.Fatalf("Error fetching platform wallet address: %v\n", err)
+}
+```
+
+
+
+
+
+```java wrap
+var customerWalletAddress = client.walletAddress().get("https://cloudninebank.example.com/customer");
+var merchantWalletAddress = client.walletAddress().get("https://happylifebank.example.com/merchant");
+var platformWalletAddress = client.walletAddress().get("https://coolwallet.example.com/platform");
+```
+
+
+
+
+
+```csharp wrap
+var customerWalletAddress = await client.GetWalletAddressAsync("https://cloudninebank.example.com/customer");
+var merchantWalletAddress = await client.GetWalletAddressAsync("https://happylifebank.example.com/merchant");
+var platformWalletAddress = await client.GetWalletAddressAsync("https://happylifebank.example.com/platform");
+```
+
+
+
+
diff --git a/docs/src/content/docs/partials/code/guides/split-payments/_grant-request-incoming-payments.mdx b/docs/src/content/docs/partials/code/guides/split-payments/_grant-request-incoming-payments.mdx
new file mode 100644
index 00000000..18180036
--- /dev/null
+++ b/docs/src/content/docs/partials/code/guides/split-payments/_grant-request-incoming-payments.mdx
@@ -0,0 +1,200 @@
+import { Tabs, TabItem } from '@astrojs/starlight/components'
+
+
+
+
+```ts wrap
+// Merchant
+const merchantIncomingPaymentGrant = await client.grant.request(
+ {
+ url: merchantWalletAddress.authServer
+ },
+ {
+ access_token: {
+ access: [
+ {
+ type: 'incoming-payment',
+ actions: ['create']
+ }
+ ]
+ }
+ }
+)
+// Platform
+const platformIncomingPaymentGrant = await client.grant.request(
+ {
+ url: platformWalletAddress.authServer
+ },
+ {
+ access_token: {
+ access: [
+ {
+ type: 'incoming-payment',
+ actions: ['create']
+ }
+ ]
+ }
+ }
+)
+```
+
+
+
+
+```rust wrap
+use open_payments::types::{AccessTokenRequest, AccessItem, IncomingPaymentAction, GrantRequest};
+let incoming_access = AccessTokenRequest {
+ access: vec![AccessItem::IncomingPayment { actions: vec![IncomingPaymentAction::Create], identifier: None }],
+};
+let merchant_grant_request = GrantRequest::new(incoming_access.clone(), None);
+let platform_grant_request = GrantRequest::new(incoming_access, None);
+let merchant_incoming_payment_grant = client
+ .grant()
+ .request(&merchant_wallet_address.auth_server, &merchant_grant_request)
+ .await?;
+let platform_incoming_payment_grant = client
+ .grant()
+ .request(&platform_wallet_address.auth_server, &platform_grant_request)
+ .await?;
+```
+
+
+
+
+```php wrap
+// Merchant
+$merchantIncomingPaymentGrant = $client->grant()->request(
+ [
+ 'url' => $merchantWalletAddress->authServer
+ ],
+ [
+ 'access_token' => [
+ 'access' => [
+ [
+ 'type' => 'incoming-payment',
+ 'actions' => ['create']
+ ]
+ ]
+ ]
+ ]
+);
+// Platform
+$platformIncomingPaymentGrant = $client->grant()->request(
+ [
+ 'url' => $platformWalletAddress->authServer
+ ],
+ [
+ 'access_token' => [
+ 'access' => [
+ [
+ 'type' => 'incoming-payment',
+ 'actions' => ['create']
+ ]
+ ]
+ ]
+ ]
+);
+```
+
+
+
+
+
+```go wrap
+incomingAccess := as.AccessIncoming{
+ Type: as.IncomingPayment,
+ Actions: []as.AccessIncomingActions{as.AccessIncomingActionsCreate},
+}
+accessItem := as.AccessItem{}
+if err := accessItem.FromAccessIncoming(incomingAccess); err != nil {
+ log.Fatalf("Error creating AccessItem: %v\n", err)
+}
+accessToken := struct {
+ Access as.Access `json:"access"`
+}{
+ Access: []as.AccessItem{accessItem},
+}
+// Merchant
+merchantIncomingPaymentGrant, err := client.Grant.Request(context.TODO(), op.GrantRequestParams{
+ URL: *merchantWalletAddress.AuthServer,
+ RequestBody: as.GrantRequestWithAccessToken{AccessToken: accessToken},
+})
+if err != nil {
+ log.Fatalf("Error requesting merchant incoming payment grant: %v\n", err)
+}
+// Platform
+platformIncomingPaymentGrant, err := client.Grant.Request(context.TODO(), op.GrantRequestParams{
+ URL: *platformWalletAddress.AuthServer,
+ RequestBody: as.GrantRequestWithAccessToken{AccessToken: accessToken},
+})
+if err != nil {
+ log.Fatalf("Error requesting platform incoming payment grant: %v\n", err)
+}
+```
+
+
+
+
+
+```java wrap
+// Merchant
+var merchantIncomingPaymentGrant = client.auth().grant().incomingPayment(
+ merchantWalletAddress
+);
+
+// Platform
+var platformIncomingPaymentGrant = client.auth().grant().incomingPayment(
+ platformWalletAddress
+);
+```
+
+
+
+
+
+```csharp wrap
+// Merchant
+var merchantIncomingPaymentGrant = await client.RequestGrantAsync(
+ new RequestArgs
+ {
+ Url = merchantWalletAddress.AuthServer,
+ },
+ new GrantCreateBody
+ {
+ AccessToken = new AccessToken
+ {
+ Access =
+ [
+ new IncomingAccess
+ {
+ Actions = [Actions.Create]
+ }
+ ]
+ }
+ }
+);
+// Platform
+var platformIncomingPaymentGrant = await client.RequestGrantAsync(
+ new RequestArgs
+ {
+ Url = platformWalletAddress.AuthServer,
+ },
+ new GrantCreateBody
+ {
+ AccessToken = new AccessToken
+ {
+ Access =
+ [
+ new IncomingAccess
+ {
+ Actions = [Actions.Create]
+ }
+ ]
+ }
+ }
+);
+```
+
+
+
+
diff --git a/docs/src/content/docs/partials/code/guides/split-payments/_grant-request-outgoing-payment.mdx b/docs/src/content/docs/partials/code/guides/split-payments/_grant-request-outgoing-payment.mdx
new file mode 100644
index 00000000..b8951fa3
--- /dev/null
+++ b/docs/src/content/docs/partials/code/guides/split-payments/_grant-request-outgoing-payment.mdx
@@ -0,0 +1,253 @@
+import { Tabs, TabItem } from '@astrojs/starlight/components'
+
+
+
+
+```ts wrap
+combinedQuoteAmount = '10000' // 9900 + 100
+
+const pendingCustomerOutgoingPaymentGrant = await client.grant.request(
+ {
+ url: customerWalletAddress.authServer
+ },
+ {
+ access_token: {
+ access: [
+ {
+ identifier: customerWalletAddress.id,
+ type: 'outgoing-payment',
+ actions: ['create'],
+ limits: {
+ debitAmount: {
+ assetCode: 'USD',
+ assetScale: 2,
+ value: combinedQuoteAmount
+ }
+ }
+ }
+ ]
+ },
+ interact: {
+ start: ['redirect'],
+ finish: {
+ method: 'redirect',
+ uri: 'https://paymentplatform.example/finish/{...}', // where to redirect the customer after they've completed interaction
+ nonce: NONCE
+ }
+ }
+ }
+)
+```
+
+
+
+
+```rust wrap
+use open_payments::types::{AccessTokenRequest, AccessItem, OutgoingPaymentAction, InteractRequest, InteractStart, InteractFinish, InteractFinishMethod, AccessLimits, Amount, GrantRequest};
+
+let merchant_amount = match merchant_quote.debit_amount.as_ref() {
+ Some(a) => &a.value,
+ None => {
+ eprintln!("Missing debit_amount on merchant quote");
+ return Ok(());
+ }
+};
+let platform_amount = match platform_quote.debit_amount.as_ref() {
+ Some(a) => &a.value,
+ None => {
+ eprintln!("Missing debit_amount on platform quote");
+ return Ok(());
+ }
+};
+let merchant_value = match merchant_amount.parse::() {
+ Ok(v) => v,
+ Err(_) => {
+ eprintln!("Invalid merchant debit_amount value");
+ return Ok(());
+ }
+};
+let platform_value = match platform_amount.parse::() {
+ Ok(v) => v,
+ Err(_) => {
+ eprintln!("Invalid platform debit_amount value");
+ return Ok(());
+ }
+};
+let combined_quote_amount = merchant_value + platform_value;
+let outgoing_access = AccessTokenRequest {
+ access: vec![AccessItem::OutgoingPayment {
+ identifier: Some(customer_wallet_address.id.clone()),
+ actions: vec![OutgoingPaymentAction::Create],
+ limits: Some(AccessLimits { debit_amount: Some(Amount { value: combined_quote_amount.to_string(), asset_code: "USD".into(), asset_scale: 2 }), ..Default::default() }),
+ }],
+};
+let interact = InteractRequest { start: Some(vec![InteractStart::Redirect]), finish: Some(InteractFinish { method: InteractFinishMethod::Redirect, uri: Some("https://paymentplatform.example/finish/{...}".into()), nonce: Some("NONCE".into()) }) };
+let outgoing_grant_request = GrantRequest::new(outgoing_access, Some(interact));
+let pending_customer_outgoing_payment_grant = client
+ .grant()
+ .request(&customer_wallet_address.auth_server, &outgoing_grant_request)
+ .await?;
+```
+
+
+
+
+
+```php wrap
+$combinedQuoteAmount = bcadd($merchantQuote->debitAmount->value, $platformQuote->debitAmount->value);
+
+$pendingCustomerOutgoingPaymentGrant = $client->grant()->request(
+ [
+ 'url' => $customerWalletAddress->authServer
+ ],
+ [
+ 'access_token' => [
+ 'access' => [
+ [
+ 'identifier' => $customerWalletAddress->id,
+ 'type' => 'outgoing-payment',
+ 'actions' => ['create'],
+ 'limits' => [
+ 'debitAmount' => [
+ 'assetCode' => 'USD',
+ 'assetScale' => 2,
+ 'value' => $combinedQuoteAmount
+ ]
+ ]
+ ]
+ ]
+ ],
+ 'interact' => [
+ 'start' => ['redirect'],
+ 'finish' => [
+ 'method' => 'redirect',
+ 'uri' => 'https://paymentplatform.example/finish/{...}', // where to redirect the customer after they've completed interaction
+ 'nonce' => 'NONCE'
+ ]
+ ]
+ ]
+);
+```
+
+
+
+
+
+```go wrap
+combinedQuoteAmount := "10000" // merchantQuote.DebitAmount.Value + platformQuote.DebitAmount.Value
+limits := as.LimitsOutgoing{}
+if err := limits.FromLimitsOutgoing1(as.LimitsOutgoing1{
+ DebitAmount: as.Amount{
+ Value: combinedQuoteAmount,
+ AssetCode: "USD",
+ AssetScale: 2,
+ },
+}); err != nil {
+ log.Fatalf("Error creating limits: %v\n", err)
+}
+outgoingAccess := as.AccessOutgoing{
+ Type: as.OutgoingPayment,
+ Actions: []as.AccessOutgoingActions{as.AccessOutgoingActionsCreate},
+ Identifier: *customerWalletAddress.Id,
+ Limits: &limits,
+}
+outgoingAccessItem := as.AccessItem{}
+if err := outgoingAccessItem.FromAccessOutgoing(outgoingAccess); err != nil {
+ log.Fatalf("Error creating AccessItem: %v\n", err)
+}
+outgoingAccessToken := struct {
+ Access as.Access `json:"access"`
+}{
+ Access: []as.AccessItem{outgoingAccessItem},
+}
+interact := &as.InteractRequest{
+ Start: []as.InteractRequestStart{as.InteractRequestStartRedirect},
+ Finish: &as.InteractRequestFinish{
+ Method: as.Redirect,
+ Uri: "https://paymentplatform.example/finish/{...}", // where to redirect the customer after they've completed interaction
+ Nonce: NONCE,
+ },
+}
+pendingCustomerOutgoingPaymentGrant, err := client.Grant.Request(context.TODO(), op.GrantRequestParams{
+ URL: *customerWalletAddress.AuthServer,
+ RequestBody: as.GrantRequestWithAccessToken{
+ AccessToken: outgoingAccessToken,
+ Interact: interact,
+ },
+})
+if err != nil {
+ log.Fatalf("Error requesting outgoing payment grant: %v\n", err)
+}
+```
+
+
+
+
+```java wrap
+var merchantDebit = new BigDecimal(merchantQuote.getDebitAmount().getValue());
+var platformDebit = new BigDecimal(platformQuote.getDebitAmount().getValue());
+var combinedQuoteAmount = merchantDebit.add(platformDebit);
+
+var debitAmount = Amount.build(
+ combinedQuoteAmount,
+ merchantQuote.getDebitAmount().getAssetCode(),
+ merchantQuote.getDebitAmount().getAssetScale()
+);
+
+var urlToOpen = "https://paymentplatform.example/finish/{...}";
+
+var opContinueInteract = client.auth().grant().continuation(
+ customerWalletAddress,
+ debitAmount,
+ URI.create(urlToOpen),
+ "NONCE"
+);
+```
+
+
+
+
+
+```csharp wrap
+var combinedQuoteAmount = "10000"; // 9900 + 100
+
+var pendingCustomerOutgoingPaymentGrant = await client.RequestGrantAsync(
+ new RequestArgs
+ {
+ Url = customerWalletAddress.AuthServer,
+ },
+ new GrantCreateBodyWithInteract
+ {
+ AccessToken = new AccessToken
+ {
+ Access =
+ [
+ new OutgoingAccess
+ {
+ Identifier = customerWalletAddress.Id,
+ Actions = [Actions.Create],
+ Limits = new OutgoingAccessLimits
+ {
+ DebitAmount = new AuthAmount(combinedQuoteAmount, "USD", 2),
+ }
+ }
+ ]
+ },
+ Interact = new InteractRequest
+ {
+ Start = [Start.Redirect],
+ Finish = new Finish
+ {
+ Method = FinishMethod.Redirect,
+ Uri = new Uri(
+ "https://localhost"), // where to redirect your user after they've completed the interaction
+ Nonce = NONCE
+ }
+ }
+ }
+);
+```
+
+
+
+
diff --git a/docs/src/content/docs/partials/code/guides/split-payments/_grant-request-quote.mdx b/docs/src/content/docs/partials/code/guides/split-payments/_grant-request-quote.mdx
new file mode 100644
index 00000000..804b549f
--- /dev/null
+++ b/docs/src/content/docs/partials/code/guides/split-payments/_grant-request-quote.mdx
@@ -0,0 +1,127 @@
+import { Tabs, TabItem } from '@astrojs/starlight/components'
+
+
+
+
+ ```ts wrap
+ const customerQuoteGrant = await client.grant.request(
+ {
+ url: customerWalletAddress.authServer
+ },
+ {
+ access_token: {
+ access: [
+ {
+ type: 'quote',
+ actions: ['create']
+ }
+ ]
+ }
+ }
+ )
+ ```
+
+
+
+
+
+ ```rust wrap
+ use open_payments::types::{AccessTokenRequest, AccessItem, QuoteAction, GrantRequest};
+ let quote_access = AccessTokenRequest {
+ access: vec![AccessItem::Quote { actions: vec![QuoteAction::Create] }],
+ };
+ let customer_grant_request = GrantRequest::new(quote_access, None);
+ let customer_quote_grant = client
+ .grant()
+ .request(&customer_wallet_address.auth_server, &customer_grant_request)
+ .await?;
+ ```
+
+
+
+
+
+```php wrap
+ $customerQuoteGrant = $client->grant()->request(
+ [
+ 'url' => $customerWalletAddress->authServer
+ ],
+ [
+ 'access_token' => [
+ 'access' => [
+ [
+ 'type' => 'quote',
+ 'actions' => ['create']
+ ]
+ ]
+ ]
+ ]
+ );
+```
+
+
+
+
+
+```go wrap
+quoteAccess := as.AccessQuote{
+ Type: as.Quote,
+ Actions: []as.AccessQuoteActions{as.Create},
+}
+quoteAccessItem := as.AccessItem{}
+if err := quoteAccessItem.FromAccessQuote(quoteAccess); err != nil {
+ log.Fatalf("Error creating AccessItem: %v\n", err)
+}
+quoteAccessToken := struct {
+ Access as.Access `json:"access"`
+}{
+ Access: []as.AccessItem{quoteAccessItem},
+}
+customerQuoteGrant, err := client.Grant.Request(context.TODO(), op.GrantRequestParams{
+ URL: *customerWalletAddress.AuthServer,
+ RequestBody: as.GrantRequestWithAccessToken{AccessToken: quoteAccessToken},
+})
+if err != nil {
+ log.Fatalf("Error requesting quote grant: %v\n", err)
+}
+```
+
+
+
+
+
+```java wrap
+var customerQuoteGrant = client.auth().grant().quote(
+ customerWalletAddress
+);
+```
+
+
+
+
+
+```csharp wrap
+var customerQuoteGrant = await client.RequestGrantAsync(
+ new RequestArgs
+ {
+ Url = customerWalletAddress.AuthServer,
+ },
+ new GrantCreateBody
+ {
+ AccessToken = new AccessToken
+ {
+ Access =
+ [
+ new QuoteAccess
+ {
+ Actions = [Actions.Create]
+ }
+ ]
+ }
+ }
+);
+```
+
+
+
+
diff --git a/docs/src/content/docs/partials/code/guides/split-payments/_request-a-grant-continuation.mdx b/docs/src/content/docs/partials/code/guides/split-payments/_request-a-grant-continuation.mdx
new file mode 100644
index 00000000..326b1ce0
--- /dev/null
+++ b/docs/src/content/docs/partials/code/guides/split-payments/_request-a-grant-continuation.mdx
@@ -0,0 +1,93 @@
+import { Tabs, TabItem } from '@astrojs/starlight/components'
+
+
+
+
+ ```ts wrap
+ const customerOutgoingPaymentGrant = await client.grant.continue(
+ {
+ url: pendingCustomerOutgoingPaymentGrant.continue.uri,
+ accessToken: pendingCustomerOutgoingPaymentGrant.continue.access_token.value
+ },
+ {
+ interact_ref: interactRef
+ }
+ )
+ ```
+
+
+
+
+```rust wrap
+let customer_outgoing_payment_grant = client
+ .grant()
+ .continue_grant(
+ if let Some(continue_field) = &pending_customer_outgoing_payment_grant.continue_field { &continue_field.uri } else { eprintln!("Missing continue field on pending grant"); return Ok(()); },
+ &interact_ref,
+ if let Some(continue_field) = &pending_customer_outgoing_payment_grant.continue_field { Some(&continue_field.access_token.value) } else { None },
+ )
+ .await?;
+```
+
+
+
+
+
+```php wrap
+$customerOutgoingPaymentGrant = $client->grant()->continue(
+ [
+ 'url' => $pendingCustomerOutgoingPaymentGrant->continue->uri,
+ 'accessToken' => $pendingCustomerOutgoingPaymentGrant->continue->access_token->value
+ ],
+ [
+ 'interact_ref' => $interactRef
+ ]
+);
+```
+
+
+
+
+
+```go wrap
+customerOutgoingPaymentGrant, err := client.Grant.Continue(context.TODO(), op.GrantContinueParams{
+ URL: pendingCustomerOutgoingPaymentGrant.Continue.Uri,
+ AccessToken: pendingCustomerOutgoingPaymentGrant.Continue.AccessToken.Value,
+ InteractRef: INTERACT_REF
+})
+if err != nil {
+ log.Fatalf("Error continuing grant: %v\n", err)
+}
+```
+
+
+
+
+```java wrap
+var customerOutgoingPaymentGrant = client.auth().grant().finalize(
+ opContinueInteract,
+ interactRef
+);
+```
+
+
+
+
+
+```csharp wrap
+var customerOutgoingPaymentGrant = await client.ContinueGrantAsync(
+ new AuthRequestArgs
+ {
+ Url = pendingCustomerOutgoingPaymentGrant.Continue.Uri,
+ AccessToken = pendingCustomerOutgoingPaymentGrant.Continue.AccessToken.Value
+ },
+ new GrantContinueBody
+ {
+ InteractRef = interactRef
+ }
+);
+```
+
+
+
+