Skip to content
GitHub

Create a split-payments application

This tutorial guides you to build an application that supports split-payments using the Open Payments SDK. Split-payments are common on online marketplaces where multiple merchants sell their goods and services on one platform. When a customer purchases an item on the marketplace, you, as the platform operator, can split the payment between yourself and the merchant according to a percentage split. Airbnb and Uber are examples of platforms where payments made by guests and riders are split between the platform on one side and hosts and drivers on the other, respectively.

In the split-payments use case, there are three parties to the transaction:

  • Customer: the purchaser of a good or service on the marketplace
  • Merchant: the seller of a good or service on the marketplace
  • Platform: the operator of the marketplace

In this tutorial you will assume the role of the platform operator integrating split-payments using Open Payments with your online marketplace.

Endpoints

Prerequisites

Additional configuration

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

Add the following to tsconfig.json

{
"compilerOptions": {
"target": "ES2022",
"module": "ES2022"
}
}

Import dependencies

Import createAuthenticatedClient from the Open Payments SDK package.

Import dependencies

import { createAuthenticatedClient } from "@interledger/open-payments";
Copied!

Create an authenticated Open Payments client

Create an Open Payments-authenticated client by providing the following properties:

  • walletAddressURL : your Open Payments-enabled wallet address that your client will use to authenticate itself to one or more authorization servers.
  • privateKey : the EdDSA-Ed25519 key or preferably the absolute or relative file path to the key that is bound to your wallet address. A public key signed with this private key must be made available as a public JWK document at {walletAddressUrl}/jwks.json url.
  • keyId : the identifier of the private key and the corresponding public key.

Initialize Open Payments client

const client = await createAuthenticatedClient({
  walletAddressUrl: WALLET_ADDRESS,
  privateKey: PRIVATE_KEY_PATH,
  keyId: KEY_ID,
});
Copied!

Steps

1. Fetch wallet addresses

Fetch the wallet addresses of the buyer, merchant, and your marketplace platform. In this example, we assume each party has their Open Payments-enabled account with a different account servicing entity.

const customerWalletAddress = await client.walletAddress.get({
url: 'https://gatehub.net/buyer'
})
const merchantWalletAddress = await client.walletAddress.get({
url: 'https://chimoney.io/merchant'
})
const platformWalletAddress = await client.walletAddress.get({
url: 'https://interledger.app/platform'
})

2. Request Incoming Payment grants

Request incomingPayment grants from your wallet authorization server as well as from the merchant wallet authorization server.

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

3. Create Incoming Payment resources

Create incomingPayment resources using the access tokens returned from the authorizations servers in step 2. Since this example assumes the merchant and the platform operator are using different account servicing entities, the incomingPayment resources will be created on the respective resource servers.

In this example you will split the payment and give the merchant 99% on a $100 payment, while retaining 1% for your fee as the platform operator.

const merchantIncomingPayment = await client.incomingPayment.create(
{
url: new URL(WALLET_ADDRESS).origin,
accessToken: INCOMING_PAYMENT_ACCESS_TOKEN
},
{
merchantWalletAddress: WALLET_ADDRESS,
incomingAmount: {
value: '9900',
assetCode: 'USD',
assetScale: 2
},
expiresAt: new Date(Date.now() + 60_000 * 10).toISOString()
}
)

4. Request quote grants

Request two quote grants from the customer wallet authorization server, as there are two recipients on this payment.

const grant = await client.grant.request(
{
url: walletAddress.authServer
},
{
access_token: {
access: [
{
type: 'quote',
actions: ['create', 'read']
}
]
}
}
)

5. Request quotes

Request two quote resources from the customer wallet resource server using the access tokens returned in Step 4. Specify the respective incomingPayment URLs returned in Step 3 for each of the quotes.

const quote = await client.quote.create(
{
url: new URL(WALLET_ADDRESS).origin,
accessToken: QUOTE_ACCESS_TOKEN
},
{
method: 'ilp',
walletAddress: WALLET_ADDRESS,
receiver: INCOMING_PAYMENT_URL
}
)

5. Request an interactive outgoing payment grant

Request an outgoingPayment grant from the customer wallet authorization server.

Add the limits object with the following properties:

  • receiveAmount : the total maximum amount to be received and then split between the merchant’s wallet and your platform’s wallet.
const grant = await client.grant.request(
{
url: customerWalletAddress.authServer
},
{
access_token: {
access: [
{
identifier: merchantWalletAddress.id,
type: 'outgoing-payment',
actions: ['read', 'create'],
limits: {
receiveAmount: {
assetCode: receiveAmount.assetCode,
assetScale: receiveAmount.assetScale,
value: receiveAmount.value
}
}
}
]
},
interact: {
start: ['redirect'],
finish: {
method: 'redirect',
uri: 'http://localhost:3344',
nonce: NONCE
}
}
}
)

6. Create outgoing payments

Create two outgoingPayment resources on the customer wallet resource server using the access token returned by the authorization server in the grant request in step 5.

Add the following properties:

  • walletAddress : the URL of the customer wallet address.
  • quoteId : the URL of the quote specifying the payment amount to be paid to the merchant.
const outgoingPayment = await client.outgoingPayment.create(
{
url: new URL(WALLET_ADDRESS).origin,
accessToken: OUTGOING_PAYMENT_ACCESS_TOKEN
},
{
walletAddress: WALLET_ADDRESS,
quoteId: QUOTE_URL
}
)