Get an outgoing payment grant for future payments
Often, a transaction starts with the client getting the payment recipient’s details and asking the recipient’s ASE for permission to send money. However, Open Payments also supports a different approach: the client gets permission from the sender’s ASE to send money before knowing who the recipient will be. Web Monetization’s pay-as-you-browse model uses this approach.
Real-life use case: Web Monetization browser extension
The Web Monetization extension uses Open Payments to issue continuous outgoing payments to a web monetized site. The payments are issued on behalf of the user for as long as the user is on the site. The extension has no idea who the recipient will be until the user visits the site.
Setting up the extension requires the user to connect it to their wallet account. They specify a maximum amount they’re willing to spend and select whether the amount should automatically renew each month. The extension then receives an outgoing payment grant from the user’s wallet provider, allowing the extension to initiate future payments.
Scenario
Section titled “Scenario”For this guide, you’ll assume the role of an app developer. The guide explains how to allow your app’s user to send payments of up to $100 CAD a month for three months without specifying a recipient beforehand.
Endpoints
Section titled “Endpoints”- GET Get Wallet Address
- POST Grant Request
- POST Grant Continuation Request
1. Get wallet address information
Section titled “1. Get wallet address information”Let’s assume your user saved their wallet address in their account profile when setting up your app. Call the GET Get Wallet Address API.
const userWalletAddress = await client.walletAddress.get({ url: 'https://cloudninebank.example.com/user'})
Example response
{ "id": "https://cloudninebank.example.com/user", "assetCode": "CAD", "assetScale": 2, "authServer": "https://auth.cloudninebank.example.com/", "resourceServer": "https://cloudninebank.example.com/op"}
2. Request an interactive outgoing payment grant
Section titled “2. Request an interactive outgoing payment grant”Use the authorization server information received in the previous step to call the POST Grant Request API.
This call obtains a token that allows your app to request outgoing payment resources be created on your user’s wallet account.
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.
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, }, }, },);
Example response
{ "interact": { "redirect": "https://auth.interledger-test.dev/{...}", // uri to redirect the user to, to begin interaction "finish": "..." // unique key to secure the callback }, "continue": { "access_token": { "value": "..." // access token for continuing the outgoing payment grant request }, "uri": "https://auth.interledger-test.dev/continue/{...}", // uri for continuing the outgoing payment grant request "wait": 30 }}
About the interval
Section titled “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:
R3/
is the number of repetitions - three.2025-05-20
is the start date of the repeating interval - 20 May 2025T13:00:00Z/
is the start time of the repeating interval - 1:00 PM UTC.P1M
is the period between each interval - one month. Used withR3/
, you have a grant that’s valid once a month for three months.
Altogether, your user can send up to $100 CAD from:
- 1 PM UTC on 20 May 2025 through 12:59 PM UTC on 20 June 2025
- 1 PM UTC on 20 June 2025 through 12:59 PM UTC on 20 July 2025
- 1 PM UTC on 20 July 2025 through 12:59 PM UTC on 20 August 2025
3. Start interaction with your user
Section titled “3. Start interaction with your user”Once the client receives the authorization server’s response, it must send the user to the interact.redirect
URI contained in the response. This starts the interaction flow.
The response also includes a continue
object, which is essential for managing the interaction and obtaining explicit user consent for outgoing payment grants. The continue
object contains an access token and a URI that the client will use to finalize the grant request after the user has completed their interaction with the identity provider (IdP). This ensures that the client can securely obtain the necessary permissions to proceed with the payment process.
4. Finish interaction with your user
Section titled “4. Finish interaction with your user”The user interacts with the authorization server through the server’s interface and approves or denies the grant.
Provided the user approves the grant, the authorization server:
- Sends the user to the
finish.uri
provided in the interactive outgoing payment grant request. The means by which the server sends the user to the URI is out of scope, but common options include redirecting the user from a web page and launching the system browser with the target URI. - Secures the redirect by adding a unique hash, allowing your client to validate the
finish
call, and an interaction reference as query parameters to the URI.
5. Request a grant continuation
Section titled “5. Request a grant continuation”In our example, we’re assuming the IdP the user interacted with has a user interface. When the interaction completes, your user is directed back to your app. Now the client can make a grant continuation request.
Call the POST Grant Continuation Request API. This call requests an access token that allows your app to request outgoing payment resources be created on the user’s wallet account.
Issue the request to the continue.uri
provided in the initial outgoing payment grant response (Step 2).
Include the interact_ref
returned in the redirect URI’s query parameters.
const userOutgoingPaymentGrant = await client.grant.continue( { accessToken: pendingUserOutgoingPaymentGrant.continue.acces_token.value, url: pendingUserOutgoingPaymentGrant.continue.uri, }, { interact_ref: 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
{ "access_token": { "value": "...", // final access token required before creating outgoing payments "manage": "https://auth.cloudninebank.example.com/token/{...}", // management uri for access token "access": [ { "type": "outgoing-payment", "actions": ["create", "read"], "identifier": "https://cloudninebank.example.com/user", } ] }, "continue": { "access_token": { "value": "..." // access token for continuing the request }, "uri": "https://auth.cloudninebank.example.com/continue/{...}" // continuation request uri }}