Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add methods (ilp payment method), remove references to connection #284

Merged
merged 21 commits into from
Sep 28, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/sixty-trainers-ring.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@interledger/open-payments': major
---

BREAKING: Introducing the concept of payment methods (on incoming payments) which allow returing a list of possible payment methods to pay into. For now, only one payment method is supported: ILP. Quote creation requires specifying a payment method for which to quote on.
113 changes: 91 additions & 22 deletions openapi/resource-server.yaml
Original file line number Diff line number Diff line change
@@ -1,39 +1,35 @@
openapi: 3.1.0
info:
title: Open Payments
version: '1.3'
version: '1.4'
license:
name: Apache 2.0
identifier: Apache-2.0
description: |-
The Open Payments API is a simple REST API with 5 resource types: **wallet address**, **quote**, **connection**, **incoming payment** and **outgoing payment**.
The Open Payments API is a simple REST API with 4 resource types: **wallet address**, **quote**, **incoming payment** and **outgoing payment**.

The *service endpoint* for the API is always the URL of the wallet address resource and all other resources (except connections) are sub-resources of the wallet address.
The *service endpoint* for the API is always the URL of the wallet address resource and all other resources are sub-resources of the wallet address.

An incoming payment defines meta data that is automatically attached to payments made into the wallet address under that incoming payment. This facilitates automation of processes like reconciliation of payment into the wallet address with external systems.

An outgoing payment is an instruction to make a payment out of the wallet address.

A quote is a commitment from the Account Servicing Entity to deliver a particular amount to a receiver when sending a particular amount from the wallet address. It is only valid for a limited time.

For privacy reasons a connection resource is not a sub-resource of a wallet address.

All resource and collection resource representations use JSON and the media-type `application/json`.

The `wallet address` resource has three collections of sub-resources:
1. `/incoming-payments` contains the **incoming payment** sub-resources
2. `/outgoing-payments` contains the **outgoing payment** sub-resources
3. `/quotes` contains the **quote** sub-resources

There is no normative path for **connection** resources. In this documentation we use the path `/connections` but implementations may use any arbitrary path.

Access to resources and permission to execute the methods exposed by the API is determined by the grants given to the client represented by an access token used in API requests.
summary: An API for open access to financial accounts to send and receive payments.
contact:
email: [email protected]
servers:
- url: '/'
description: 'Server for wallet address subresources or Connection resources (ie https://openpayments.guide/alice)'
description: 'Server for wallet address subresources (ie https://openpayments.guide/alice)'
tags:
- name: wallet-address
description: wallet address operations
Expand All @@ -43,8 +39,6 @@ tags:
description: outgoing payment operations
- name: quote
description: quote operations
- name: stream-connection
description: interledger STREAM connections
paths:
/:
get:
Expand Down Expand Up @@ -107,7 +101,7 @@ paths:
content:
application/json:
schema:
$ref: '#/components/schemas/incoming-payment'
$ref: '#/components/schemas/incoming-payment-with-methods'
examples:
New Incoming Payment for $25:
value:
Expand All @@ -127,7 +121,10 @@ paths:
externalRef: INV2022-02-0137
createdAt: '2022-03-12T23:20:50.52Z'
updatedAt: '2022-04-01T10:24:36.11Z'
'401':
methods:
- type: ilp
ilpAddress: g.ilp.iwuyge987y.98y08y
sharedSecret: 1c7eaXa4rd2fFOBl1iydvCT1tV5TbM3RW1WLCafu_JA'401'
$ref: '#/components/responses/401'
'403':
$ref: '#/components/responses/403'
Expand Down Expand Up @@ -517,6 +514,7 @@ paths:
value: '2198'
assetCode: EUR
assetScale: 2
method: ilp
createdAt: '2022-03-12T23:20:50.52Z'
expiresAt: '2022-04-12T23:20:50.52Z'
'400':
Expand All @@ -529,16 +527,22 @@ paths:
content:
application/json:
examples:
Create fixed-send-amount quote for $25 to an ILP STREAM connection:
Create quote for an `receiver` that is an Incoming Payment with an `incomingAmount`:
value:
receiver: 'https://openpayments.guide/incoming-payments/37a0d0ee-26dc-4c66-89e0-01fbf93156f7'
method: ilp
Create fixed-send amount quote for $25:
value:
receiver: 'https://openpayments.guide/connections/45a0d0ee-26dc-4c66-89e0-01fbf93156f7'
receiver: 'https://openpayments.guide/incoming-payments/37a0d0ee-26dc-4c66-89e0-01fbf93156f7'
method: ilp
debitAmount:
value: '2500'
assetCode: USD
assetScale: 2
Create fixed-receive-amount quote for $25:
Create fixed-receive amount quote for $25:
value:
receiver: 'https://openpayments.guide/incoming-payments/37a0d0ee-26dc-4c66-89e0-01fbf93156f7'
method: ilp
receiveAmount:
value: '2500'
assetCode: USD
Expand All @@ -549,29 +553,38 @@ paths:
properties:
receiver:
$ref: ./schemas.yaml#/components/schemas/receiver
method:
$ref: '#/components/schemas/payment-method'
required:
- receiver
- method
additionalProperties: false
- description: Create a quote with a fixed-receive amount
properties:
receiver:
$ref: ./schemas.yaml#/components/schemas/receiver
method:
$ref: '#/components/schemas/payment-method'
receiveAmount:
description: The fixed amount that would be paid into the receiving wallet address given a successful outgoing payment.
$ref: ./schemas.yaml#/components/schemas/amount
required:
- receiver
- method
- receiveAmount
additionalProperties: false
- description: Create a quote with a fixed send amount
- description: Create a quote with a fixed-send amount
properties:
receiver:
$ref: ./schemas.yaml#/components/schemas/receiver
method:
$ref: '#/components/schemas/payment-method'
debitAmount:
description: The fixed amount that would be sent from the sending wallet address given a successful outgoing payment.
$ref: ./schemas.yaml#/components/schemas/amount
required:
- receiver
- method
- debitAmount
additionalProperties: false
description: |-
Expand All @@ -597,7 +610,7 @@ paths:
application/json:
schema:
anyOf:
- $ref: '#/components/schemas/incoming-payment'
- $ref: '#/components/schemas/incoming-payment-with-methods'
- $ref: '#/components/schemas/public-incoming-payment'
examples:
Incoming Payment for $25 with $12.34 received so far:
Expand All @@ -619,6 +632,10 @@ paths:
metadata:
description: Thanks for the flowers!
externalRef: INV-12876
methods:
- type: ilp
ilpAddress: g.ilp.iwuyge987y.98y08y
sharedSecret: 1c7eaXa4rd2fFOBl1iydvCT1tV5TbM3RW1WLCafu_JA
'401':
$ref: '#/components/responses/401'
'403':
Expand Down Expand Up @@ -756,6 +773,7 @@ paths:
value: '2198'
assetCode: EUR
assetScale: 2
method: ilp
createdAt: '2022-03-12T23:20:50.52Z'
expiresAt: '2022-04-12T23:20:50.52Z'
'401':
Expand Down Expand Up @@ -907,15 +925,32 @@ components:
- receivedAmount
- createdAt
- updatedAt
incoming-payment-with-methods:
title: Incoming Payment with payment methods
description: An **incoming payment** resource with public details.
allOf:
- $ref: '#/components/schemas/incoming-payment'
- type: object
properties:
methods:
description: The list of payment methods supported by this incoming payment.
type: array
uniqueItems: true
minItems: 0
items:
anyOf:
- $ref: '#/components/schemas/ilp-payment-method'
required:
- methods
public-incoming-payment:
title: Public Incoming Payment
description: An **incoming payment** resource with public details.
type: object
examples:
- receivedAmount:
value: '0'
assetCode: USD
assetScale: 2
value: '0'
assetCode: USD
assetScale: 2
properties:
receiveAmount:
$ref: ./schemas.yaml#/components/schemas/amount
Expand Down Expand Up @@ -986,7 +1021,7 @@ components:
default: false
receiver:
$ref: ./schemas.yaml#/components/schemas/receiver
description: The URL of the incoming payment or ILP STREAM Connection that is being paid.
description: The URL of the incoming payment that is being paid.
receiveAmount:
$ref: ./schemas.yaml#/components/schemas/amount
description: The total amount that should be received by the receiver when this outgoing payment has been paid.
Expand Down Expand Up @@ -1036,6 +1071,7 @@ components:
value: '2500'
assetCode: USD
assetScale: 2
method: ilp
createdAt: '2022-03-12T23:20:50.52Z'
expiresAt: '2022-04-12T23:20:50.52Z'
- id: 'https://openpayments.guide/quotes/8c68d3cc-0a0f-4216-98b4-4fa44a6c88cf'
Expand All @@ -1049,6 +1085,7 @@ components:
value: '7026'
assetCode: USD
assetScale: 2
method: ilp
createdAt: '2022-03-12T23:20:50.52Z'
expiresAt: '2022-04-12T23:20:50.52Z'
additionalProperties: false
Expand All @@ -1065,13 +1102,15 @@ components:
readOnly: true
receiver:
$ref: ./schemas.yaml#/components/schemas/receiver
description: The URL of the incoming payment or ILP STREAM Connection that the quote is created for.
description: The URL of the incoming payment that the quote is created for.
receiveAmount:
$ref: ./schemas.yaml#/components/schemas/amount
description: The total amount that should be received by the receiver when the corresponding outgoing payment has been paid.
debitAmount:
$ref: ./schemas.yaml#/components/schemas/amount
description: "The total amount that should be deducted from the sender's account when the corresponding outgoing payment has been paid. "
method:
$ref: '#/components/schemas/payment-method'
expiresAt:
type: string
description: The date and time when the calculated `debitAmount` is no longer valid.
Expand All @@ -1087,6 +1126,7 @@ components:
- receiveAmount
- debitAmount
- createdAt
- method
page-info:
description: ''
type: object
Expand Down Expand Up @@ -1159,6 +1199,35 @@ components:
kty: OKP
crv: Ed25519
x: oy0L_vTygNE4IogRyn_F5GmHXdqYVjIXkWs2jky7zsI
payment-method:
type: string
enum:
- ilp
ilp-payment-method:
type: object
additionalProperties: false
properties:
type:
type: string
enum:
- ilp
ilpAddress:
type: string
maxLength: 1023
pattern: '^(g|private|example|peer|self|test[1-3]?|local)([.][a-zA-Z0-9_~-]+)+$'
description: The ILP address to use when establishing a STREAM connection.
sharedSecret:
type: string
pattern: '^[a-zA-Z0-9-_]+$'
description: The base64 url-encoded shared secret to use when establishing a STREAM connection.
required:
- type
- ilpAddress
- sharedSecret
examples:
- type: string
ilpAddress: string
sharedSecret: string
securitySchemes:
GNAP:
name: Authorization
Expand Down
19 changes: 10 additions & 9 deletions packages/open-payments/src/client/incoming-payment.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
defaultAxiosInstance,
mockIncomingPayment,
mockIncomingPaymentPaginationResult,
mockIncomingPaymentWithPaymentMethods,
mockOpenApiResponseValidators,
silentLogger
} from '../test/helpers'
Expand Down Expand Up @@ -48,7 +49,7 @@ describe('incoming-payment', (): void => {

describe('getIncomingPayment', (): void => {
test('returns incoming payment if passes validation', async (): Promise<void> => {
const incomingPayment = mockIncomingPayment()
const incomingPayment = mockIncomingPaymentWithPaymentMethods()

nock(walletAddress)
.get('/incoming-payments/1')
Expand All @@ -66,7 +67,7 @@ describe('incoming-payment', (): void => {
})

test('throws if incoming payment does not pass validation', async (): Promise<void> => {
const incomingPayment = mockIncomingPayment({
const incomingPayment = mockIncomingPaymentWithPaymentMethods({
incomingAmount: {
assetCode: 'USD',
assetScale: 2,
Expand Down Expand Up @@ -99,7 +100,7 @@ describe('incoming-payment', (): void => {
})

test('throws if incoming payment does not pass open api validation', async (): Promise<void> => {
const incomingPayment = mockIncomingPayment()
const incomingPayment = mockIncomingPaymentWithPaymentMethods()

nock(walletAddress)
.get('/incoming-payments/1')
Expand Down Expand Up @@ -129,7 +130,7 @@ describe('incoming-payment', (): void => {
`(
'returns the incoming payment on success',
async ({ incomingAmount, expiresAt, metadata }): Promise<void> => {
const incomingPayment = mockIncomingPayment({
const incomingPayment = mockIncomingPaymentWithPaymentMethods({
incomingAmount,
expiresAt,
metadata
Expand Down Expand Up @@ -162,7 +163,7 @@ describe('incoming-payment', (): void => {
value: '10'
}

const incomingPayment = mockIncomingPayment({
const incomingPayment = mockIncomingPaymentWithPaymentMethods({
incomingAmount: amount,
receivedAmount: amount,
completed: false
Expand All @@ -184,7 +185,7 @@ describe('incoming-payment', (): void => {
})

test('throws if the created incoming payment does not pass open api validation', async (): Promise<void> => {
const incomingPayment = mockIncomingPayment()
const incomingPayment = mockIncomingPaymentWithPaymentMethods()

const scope = nock(walletAddress)
.post('/incoming-payments')
Expand Down Expand Up @@ -522,7 +523,7 @@ describe('incoming-payment', (): void => {

describe('validateCreatedIncomingPayment', (): void => {
test('returns the created incoming payment if it passes validation', async (): Promise<void> => {
const incomingPayment = mockIncomingPayment({
const incomingPayment = mockIncomingPaymentWithPaymentMethods({
incomingAmount: {
assetCode: 'USD',
assetScale: 2,
Expand All @@ -541,7 +542,7 @@ describe('incoming-payment', (): void => {
})

test('throws if received amount is a non-zero value for a newly created incoming payment', async (): Promise<void> => {
const incomingPayment = mockIncomingPayment({
const incomingPayment = mockIncomingPaymentWithPaymentMethods({
receivedAmount: {
assetCode: 'USD',
assetScale: 2,
Expand All @@ -555,7 +556,7 @@ describe('incoming-payment', (): void => {
})

test('throws if the created incoming payment is completed', async (): Promise<void> => {
const incomingPayment = mockIncomingPayment({
const incomingPayment = mockIncomingPaymentWithPaymentMethods({
completed: true
})

Expand Down
Loading
Loading