Skip to content
GitHub

Create an outgoing payment grant request

The Grant Request API lets you request a grant for outgoing payment, incoming payment, and quote resources.

Before your client can call most of the Open Payments APIs, it must receive a grant from the appropriate authorization server.

The code snippets below let an authenticated client request a grant for an outgoing payment. The request to the authorization server must indicate the outgoing-payment and the actions the client wants to take at the resource server.

Outgoing payments require explicit consent, typically by the client’s user, before a grant can be issued. Consent is obtained through an interactive grant.

Any authorization server that issues interactive grants must integrate with an identity provider (IdP). When a client requests the outgoing payment grant, the authorization server provides the client with the IdP URI to redirect to.

We recommend creating a wallet account on the test wallet. Creating an account allows you to test your client against the Open Payments APIs by using an ILP-enabled wallet funded with play money.

Authenticated client required

Prerequisites

Initial configuration

If you’re using JavaScript, only do the first step.

  1. Add "type": "module" to package.json.

  2. Add the following to tsconfig.json

    {
    "compilerOptions": {
    "target": "ES2022",
    "module": "ES2022"
    }
    }
// Import dependencies
import {
createAuthenticatedClient,
isPendingGrant
} from '@interledger/open-payments'
// Initialize client
const client = await createAuthenticatedClient({
walletAddressUrl: CLIENT_WALLET_ADDRESS,
privateKey: PRIVATE_KEY_PATH,
keyId: KEY_ID
})
// Get wallet address information
const walletAddress = await client.walletAddress.get({
url: WALLET_ADDRESS
})
// Request outgoing payment grant
const grant = await client.grant.request(
{
url: walletAddress.authServer
},
{
access_token: {
access: [
{
identifier: walletAddress.id,
type: 'outgoing-payment',
actions: ['list', 'list-all', 'read', 'read-all', 'create'],
limits: {
debitAmount: {
assetCode: quote.debitAmount.assetCode,
assetScale: quote.debitAmount.assetScale,
value: quote.debitAmount.value
}
}
}
]
},
interact: {
start: ['redirect'],
finish: {
method: 'redirect',
uri: 'http://localhost:3344',
nonce: NONCE
}
}
}
)
// Check grant state
if (!isPendingGrant(grant)) {
throw new Error('Expected pending/interactive grant')
}
// Output
console.log('Please interact at the following URL:', grant.interact.redirect)
console.log('CONTINUE_ACCESS_TOKEN =', grant.continue.access_token.value)
console.log('CONTINUE_URI =', grant.continue.uri)
// Import dependencies
import {
createAuthenticatedClient,
isPendingGrant
} from '@interledger/open-payments'
// Initialize client
const client = await createAuthenticatedClient({
walletAddressUrl: CLIENT_WALLET_ADDRESS,
privateKey: PRIVATE_KEY_PATH,
keyId: KEY_ID
})
// Get wallet address information
const walletAddress = await client.walletAddress.get({
url: WALLET_ADDRESS
})
// Request outgoing payment grant
const grant = await client.grant.request(
{
url: walletAddress.authServer
},
{
access_token: {
access: [
{
identifier: walletAddress.id,
type: 'outgoing-payment',
actions: ['list', 'list-all', 'read', 'read-all', 'create'],
limits: {
debitAmount: {
assetCode: quote.debitAmount.assetCode,
assetScale: quote.debitAmount.assetScale,
value: quote.debitAmount.value
},
interval: 'R/2016-08-24T08:00:00Z/P1D'
}
}
]
},
interact: {
start: ['redirect'],
finish: {
method: 'redirect',
uri: 'http://localhost:3344',
nonce: NONCE
}
}
}
)
// Check grant state
if (!isPendingGrant(grant)) {
throw new Error('Expected pending/interactive grant')
}
// Output
console.log('Please interact at the following URL:', grant.interact.redirect)
console.log('CONTINUE_ACCESS_TOKEN =', grant.continue.access_token.value)
console.log('CONTINUE_URI =', grant.continue.uri)

For TypeScript, run tsx path/to/directory/index.ts. View full TS source

For JavaScript, run node path/to/directory/index.js. View full JS source

The subject field lets a client ask the authorization server to verify information about a subject as part of a grant request. For example, a client can use it to confirm that a wallet address identifies a particular account holder. The request must include subject.sub_ids with the subject’s id and the format (uri) the client accepts.

Subject verification requests are always interactive grants. The request must include an interact object, and the user consents through the identity provider (IdP) flow. After the user completes the interaction, the grant continuation response can include a subject object with the verified sub_ids.

Authenticated client required

Prerequisites

Initial configuration

If you’re using JavaScript, only do the first step.

  1. Add "type": "module" to package.json.

  2. Add the following to tsconfig.json

    {
    "compilerOptions": {
    "target": "ES2022",
    "module": "ES2022"
    }
    }
// Import dependencies
import {
createAuthenticatedClient,
isPendingGrant
} from '@interledger/open-payments'
// Initialize client
const client = await createAuthenticatedClient({
walletAddressUrl: CLIENT_WALLET_ADDRESS,
privateKey: PRIVATE_KEY_PATH,
keyId: KEY_ID
})
// Get wallet address information
const walletAddress = await client.walletAddress.get({
url: WALLET_ADDRESS
})
// Request subject verification grant
// TODO(docs): confirm `subject` support in TypeScript SDK
const grant = await client.grant.request(
{
url: walletAddress.authServer
},
{
subject: {
sub_ids: [
{
id: walletAddress.id,
format: 'uri'
}
]
},
client: CLIENT_WALLET_ADDRESS,
interact: {
start: ['redirect'],
finish: {
method: 'redirect',
uri: 'http://localhost:3344',
nonce: NONCE
}
}
}
)
// Check grant state
if (!isPendingGrant(grant)) {
throw new Error('Expected pending/interactive grant')
}
// Output
console.log('Please interact at the following URL:', grant.interact.redirect)
console.log('CONTINUE_ACCESS_TOKEN =', grant.continue.access_token.value)
console.log('CONTINUE_URI =', grant.continue.uri)

For TypeScript, run tsx path/to/directory/index.ts.