Create a grant request
Before a client can call most of the Open Payments APIs, it must receive a grant from the appropriate authorization server.
The request to the authorization server must indicate the access type (incoming-payment
, quote
, or outgoing-payment
) and actions the client wants to take at the resource server.
The snippets below enable a client to request a grant for each resource type.
Before you begin
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.
Request an incoming payment grant
Initial configuration
If you’re using JavaScript, only do the first step.
- Add
"type": "module"
topackage.json
. - Add the following to
tsconfig.json
{"compilerOptions": {"target": "ES2022","module": "ES2022"}}
Import dependencies
import { createAuthenticatedClient } from "@interledger/open-payments";
Copied! Initialize Open Payments client
const client = await createAuthenticatedClient({
walletAddressUrl: WALLET_ADDRESS,
privateKey: PRIVATE_KEY_PATH,
keyId: KEY_ID,
});
Copied! Get wallet address information
const walletAddress = await client.walletAddress.get({
url: WALLET_ADDRESS,
});
Copied! Request incoming payment grant
const grant = await client.grant.request(
{
url: walletAddress.authServer,
},
{
access_token: {
access: [
{
type: "incoming-payment",
actions: ["list", "read", "read-all", "complete", "create"],
},
],
},
},
);
Copied! Check grant state
if (isPendingGrant(grant)) {
throw new Error("Expected non-interactive grant");
}
Copied! Output
console.log("INCOMING_PAYMENT_ACCESS_TOKEN =", grant.access_token.value);
console.log(
"INCOMING_PAYMENT_ACCESS_TOKEN_MANAGE_URL = ",
grant.access_token.manage,
);
Copied! 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
Import dependencies
use OpenPayments\AuthClient;
use OpenPayments\Config\Config;
Copied! Initialize Open Payments client
$config = new Config($WALLET_ADDRESS, $PRIVATE_KEY, $KEY_ID);
$opClient = new AuthClient($config);
Copied! Get wallet address information
$wallet = $opClient->walletAddress()->get([
"url" => $config->getWalletAddressUrl(),
]);
Copied! Request incoming payment grant
$grant = $opClient->grant()->request(
[
"url" => $wallet->authServer,
],
[
"access_token" => [
"access" => [
[
"type" => "incoming-payment",
"actions" => ["read", "complete", "create", "list"],
],
],
],
"client" => $config->getWalletAddressUrl(),
]
);
Copied! Check grant state
if (!$grant instanceof \OpenPayments\Models\Grant) {
throw new \Error("Expected non-interactive grant");
}
Copied! Output
$output->writeln("INCOMING_PAYMENT_GRANT: " . $grant->access_token->value);
$output->writeln(
"INCOMING_PAYMENT_ACCESS_TOKEN_MANAGE_URL = " . $grant->access_token->manage
);
Copied! Request a quote grant
Initial configuration
If you’re using JavaScript, only do the first step.
- Add
"type": "module"
topackage.json
. - Add the following to
tsconfig.json
{"compilerOptions": {"target": "ES2022","module": "ES2022"}}
Import dependencies
import { createAuthenticatedClient } from "@interledger/open-payments";
Copied! Initialize Open Payments client
const client = await createAuthenticatedClient({
walletAddressUrl: WALLET_ADDRESS,
privateKey: PRIVATE_KEY_PATH,
keyId: KEY_ID,
});
Copied! Get wallet address information
const walletAddress = await client.walletAddress.get({
url: WALLET_ADDRESS,
});
Copied! Request quote grant
const grant = await client.grant.request(
{
url: walletAddress.authServer,
},
{
access_token: {
access: [
{
type: "quote",
actions: ["create", "read", "read-all"],
},
],
},
},
);
Copied! Check grant state
if (isPendingGrant(grant)) {
throw new Error("Expected non-interactive grant");
}
Copied! Output
console.log("QUOTE_ACCESS_TOKEN =", grant.access_token.value);
console.log("QUOTE_ACCESS_TOKEN_MANAGE_URL = ", grant.access_token.manage);
Copied! 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
Import dependencies
use OpenPayments\AuthClient;
use OpenPayments\Config\Config;
Copied! Initialize Open Payments client
$config = new Config($WALLET_ADDRESS, $PRIVATE_KEY, $KEY_ID);
$opClient = new AuthClient($config);
Copied! Get wallet address information
$wallet = $opClient->walletAddress()->get([
"url" => $config->getWalletAddressUrl(),
]);
Copied! Request quote grant
$grant = $opClient->grant()->request(
[
"url" => $wallet->authServer,
],
[
"access_token" => [
"access" => [
[
"type" => "quote",
"actions" => ["create", "read", "read-all"],
],
],
],
"client" => $config->getWalletAddressUrl(),
]
);
Copied! Check grant state
if ($grant instanceof \OpenPayments\Models\PendingGrant) {
throw new \Error("Expected non-interactive grant");
}
Copied! Output
$output->writeln("QUOTE_ACCESS_TOKEN: " . $grant->access_token->value);
$output->writeln(
"QUOTE_ACCESS_TOKEN_MANAGE_URL: " . $grant->access_token->manage
);
Copied! Request an outgoing payment grant
In Open Payments, outgoing payments require explicit consent, usually by the client’s user, before a grant can be issued. Consent is obtained through an interactive grant.
Open Payments also requires any authorization server that issues interactive grants to integrate with an identity provider (IdP). When the client requests the outgoing payment grant, the authorization server provides the client with the IdP URI the client should redirect to.
Initial configuration
If you’re using JavaScript, only do the first step.
- Add
"type": "module"
topackage.json
. - Add the following to
tsconfig.json
{"compilerOptions": {"target": "ES2022","module": "ES2022"}}
Import dependencies
import { createAuthenticatedClient } from "@interledger/open-payments";
Copied! Initialize Open Payments client
const client = await createAuthenticatedClient({
walletAddressUrl: WALLET_ADDRESS,
privateKey: PRIVATE_KEY_PATH,
keyId: KEY_ID,
});
Copied! Get wallet address information
const walletAddress = await client.walletAddress.get({
url: WALLET_ADDRESS,
});
Copied! 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,
},
},
},
);
Copied! Check grant state
if (!isPendingGrant(grant)) {
throw new Error("Expected interactive grant");
}
Copied! 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);
Copied! 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
Import dependencies
use OpenPayments\AuthClient;
use OpenPayments\Config\Config;
Copied! Initialize Open Payments client
$config = new Config($WALLET_ADDRESS, $PRIVATE_KEY, $KEY_ID);
$opClient = new AuthClient($config);
Copied! Get wallet address information
$wallet = $opClient->walletAddress()->get([
"url" => $config->getWalletAddressUrl(),
]);
Copied! Generate without an interval
Request outgoing payment grant
$grant = $opClient->grant()->request(
[
"url" => $wallet->authServer,
],
[
"access_token" => [
"access" => [
[
"type" => "outgoing-payment",
"actions" => ["list", "list-all", "read", "read-all", "create"],
"identifier" => $wallet->id,
"limits" => [
"receiver" => $INCOMING_PAYMENT_URL, //optional
"debitAmount" => [
"assetCode" => "USD",
"assetScale" => 2,
"value" => "130",
],
],
],
],
],
"client" => $config->getWalletAddressUrl(),
"interact" => [
"start" => ["redirect"],
"finish" => [
"method" => "redirect",
"uri" => "https://localhost/?paymentId=123423",
"nonce" => "1234567890",
],
],
]
);
Copied! Generate with an interval
Request outgoing payment grant with interval
$grant = $opClient->grant()->request(
[
"url" => $wallet->authServer,
],
[
"access_token" => [
"access" => [
[
"type" => "outgoing-payment",
"actions" => ["list", "list-all", "read", "read-all", "create"],
"identifier" => $wallet->id,
"limits" => [
"debitAmount" => [
"assetCode" => "USD",
"assetScale" => 2,
"value" => "132",
],
"interval" => "R/2025-04-22T08:00:00Z/P1D",
],
],
],
],
"client" => $config->getWalletAddressUrl(),
"interact" => [
"start" => ["redirect"],
"finish" => [
"method" => "redirect",
"uri" => "https://localhost/?paymentId=123423",
"nonce" => "1234567890",
],
],
]
);
Copied! Check grant state
if (!$grant instanceof \OpenPayments\Models\PendingGrant) {
throw new \Error("Expected interactive grant");
}
Copied! Output
$output->writeln(
"Please interact at the following URL: " . $grant->interact->redirect
);
$output->writeln(
"CONTINUE_ACCESS_TOKEN = " . $grant->continue->access_token->value
);
$output->writeln("CONTINUE_URI = " . $grant->continue->uri);
Copied!