From 8dcba344256c69818fc1c4ba49c5fe2d8ebf4153 Mon Sep 17 00:00:00 2001
From: Chen Hui Jing <1461498+huijing@users.noreply.github.com>
Date: Wed, 20 Sep 2023 14:41:39 +0300
Subject: [PATCH 01/14] Migrate documentation to Starlight
---
.github/workflows/deploy-docs.yaml | 41 +
.github/workflows/deploy-landing.yaml | 41 -
.github/workflows/test-docs-build.yml | 33 +
docs/.gitignore | 21 +
docs/README.md | 51 +
docs/astro.config.mjs | 56 +
docs/package.json | 20 +
docs/public/favicon.svg | 1 +
docs/public/img/logo.svg | 1 +
docs/src/api/auth-server.yaml | 540 ++
docs/src/api/resource-server.yaml | 1369 +++++
docs/src/api/schemas.yaml | 48 +
docs/src/assets/houston.webp | Bin 0 -> 98506 bytes
docs/src/components/OpenPaymentsLogo.astro | 4 +
docs/src/content/config.ts | 7 +
docs/src/content/docs/index.mdx | 31 +
.../content/docs/introduction/overview.mdx | 6 +
.../docs/introduction/payment-pointers.mdx | 6 +
docs/src/content/docs/security/gnap.mdx | 6 +
docs/src/env.d.ts | 2 +
docs/src/overrideIntegration.mjs | 48 +
docs/src/overrides/Header.astro | 53 +
docs/src/overrides/Search.astro | 8 +
docs/src/overrides/SocialIcons.astro | 6 +
docs/src/overrides/ThemeSelect.astro | 8 +
docs/src/styles/openpayments.css | 12 +
docs/tsconfig.json | 3 +
landing/.dockerignore | 6 -
landing/.eslintrc.json | 6 -
landing/.gitignore | 25 -
landing/README.md | 19 -
landing/components/browser.tsx | 33 -
landing/components/button.tsx | 16 -
landing/components/card.tsx | 18 -
landing/components/content.tsx | 18 -
landing/components/decor.tsx | 22 -
landing/components/footer.tsx | 41 -
landing/components/index.ts | 9 -
landing/components/logo.tsx | 29 -
landing/components/open-payments-button.tsx | 71 -
landing/components/phone.tsx | 33 -
landing/next-env.d.ts | 5 -
landing/package.json | 25 -
landing/pages/_app.tsx | 12 -
landing/pages/_document.tsx | 30 -
landing/pages/brand-guidelines.tsx | 328 --
landing/pages/index.tsx | 81 -
landing/postcss.config.js | 6 -
landing/public/Browser.svg | 19 -
landing/public/CARD Mark.svg | 5 -
landing/public/Open_Payments_Brand_Assets.zip | Bin 11668 -> 0 bytes
landing/public/Open_Payments_logomark.svg | 15 -
landing/public/Open_Payments_mark.svg | 17 -
.../public/Open_Payments_standard_logo.svg | 16 -
landing/public/Phone.svg | 19 -
landing/public/Rafiki Mark.svg | 9 -
landing/public/Specification.svg | 27 -
landing/public/favicon.svg | 15 -
landing/public/social/GitHub_Logo_White.png | Bin 31120 -> 0 bytes
landing/public/social/Slack_Mark.svg | 33 -
landing/public/social/Slack_RGB_White.svg | 47 -
landing/public/zeit.svg | 10 -
landing/styles/globals.css | 7 -
landing/tailwind.config.js | 129 -
landing/tsconfig.json | 30 -
landing/yarn.lock | 1956 -------
pnpm-lock.yaml | 4699 ++++++++++++-----
pnpm-workspace.yaml | 2 +-
68 files changed, 5889 insertions(+), 4421 deletions(-)
create mode 100644 .github/workflows/deploy-docs.yaml
delete mode 100644 .github/workflows/deploy-landing.yaml
create mode 100644 .github/workflows/test-docs-build.yml
create mode 100644 docs/.gitignore
create mode 100644 docs/README.md
create mode 100644 docs/astro.config.mjs
create mode 100644 docs/package.json
create mode 100644 docs/public/favicon.svg
create mode 100644 docs/public/img/logo.svg
create mode 100644 docs/src/api/auth-server.yaml
create mode 100644 docs/src/api/resource-server.yaml
create mode 100644 docs/src/api/schemas.yaml
create mode 100644 docs/src/assets/houston.webp
create mode 100644 docs/src/components/OpenPaymentsLogo.astro
create mode 100644 docs/src/content/config.ts
create mode 100644 docs/src/content/docs/index.mdx
create mode 100644 docs/src/content/docs/introduction/overview.mdx
create mode 100644 docs/src/content/docs/introduction/payment-pointers.mdx
create mode 100644 docs/src/content/docs/security/gnap.mdx
create mode 100644 docs/src/env.d.ts
create mode 100644 docs/src/overrideIntegration.mjs
create mode 100644 docs/src/overrides/Header.astro
create mode 100644 docs/src/overrides/Search.astro
create mode 100644 docs/src/overrides/SocialIcons.astro
create mode 100644 docs/src/overrides/ThemeSelect.astro
create mode 100644 docs/src/styles/openpayments.css
create mode 100644 docs/tsconfig.json
delete mode 100644 landing/.dockerignore
delete mode 100644 landing/.eslintrc.json
delete mode 100644 landing/.gitignore
delete mode 100644 landing/README.md
delete mode 100644 landing/components/browser.tsx
delete mode 100644 landing/components/button.tsx
delete mode 100644 landing/components/card.tsx
delete mode 100644 landing/components/content.tsx
delete mode 100644 landing/components/decor.tsx
delete mode 100644 landing/components/footer.tsx
delete mode 100644 landing/components/index.ts
delete mode 100644 landing/components/logo.tsx
delete mode 100644 landing/components/open-payments-button.tsx
delete mode 100644 landing/components/phone.tsx
delete mode 100644 landing/next-env.d.ts
delete mode 100644 landing/package.json
delete mode 100644 landing/pages/_app.tsx
delete mode 100644 landing/pages/_document.tsx
delete mode 100644 landing/pages/brand-guidelines.tsx
delete mode 100644 landing/pages/index.tsx
delete mode 100644 landing/postcss.config.js
delete mode 100644 landing/public/Browser.svg
delete mode 100644 landing/public/CARD Mark.svg
delete mode 100644 landing/public/Open_Payments_Brand_Assets.zip
delete mode 100644 landing/public/Open_Payments_logomark.svg
delete mode 100644 landing/public/Open_Payments_mark.svg
delete mode 100644 landing/public/Open_Payments_standard_logo.svg
delete mode 100644 landing/public/Phone.svg
delete mode 100644 landing/public/Rafiki Mark.svg
delete mode 100644 landing/public/Specification.svg
delete mode 100644 landing/public/favicon.svg
delete mode 100644 landing/public/social/GitHub_Logo_White.png
delete mode 100644 landing/public/social/Slack_Mark.svg
delete mode 100644 landing/public/social/Slack_RGB_White.svg
delete mode 100644 landing/public/zeit.svg
delete mode 100644 landing/styles/globals.css
delete mode 100644 landing/tailwind.config.js
delete mode 100644 landing/tsconfig.json
delete mode 100644 landing/yarn.lock
diff --git a/.github/workflows/deploy-docs.yaml b/.github/workflows/deploy-docs.yaml
new file mode 100644
index 00000000..c7ced14e
--- /dev/null
+++ b/.github/workflows/deploy-docs.yaml
@@ -0,0 +1,41 @@
+name: Deploy to GitHub Pages
+
+on:
+ # Trigger the workflow every time you push to the `main` branch
+ # Using a different branch name? Replace `main` with your branchβs name
+ push:
+ branches: [main]
+ # Allows you to run this workflow manually from the Actions tab on GitHub.
+ workflow_dispatch:
+
+# Allow this job to clone the repo and create a page deployment
+permissions:
+ contents: read
+ pages: write
+ id-token: write
+
+jobs:
+ build:
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout your repository using git
+ uses: actions/checkout@v3
+ - name: Install, build, and upload your site output
+ uses: withastro/action@v0
+ with:
+ path: ./docs # The root location of your Astro project inside the repository. (optional)
+ node-version: 18 # The specific version of Node that should be used to build your site. Defaults to 16. (optional)
+ package-manager: pnpm # The Node package manager that should be used to install dependencies and build your site. Automatically detected based on your lockfile. (optional)
+ pnpm-version: 8.x.x # If `package-manager` is set to `pnpm`, use this specific version. Defaults to `7.x.x`. (optional)
+ # resolve-dep-from-path: false # If the dependency file should be resolved from the root location of your Astro project. Defaults to `true`. (optional)
+
+ deploy:
+ needs: build
+ runs-on: ubuntu-latest
+ environment:
+ name: github-pages
+ url: ${{ steps.deployment.outputs.page_url }}
+ steps:
+ - name: Deploy to GitHub Pages
+ id: deployment
+ uses: actions/deploy-pages@v1
diff --git a/.github/workflows/deploy-landing.yaml b/.github/workflows/deploy-landing.yaml
deleted file mode 100644
index 085eb631..00000000
--- a/.github/workflows/deploy-landing.yaml
+++ /dev/null
@@ -1,41 +0,0 @@
-# This workflow will do a clean installation of node dependencies, build the Next.js project and export the static site then deploy it to Github Pages
-
-name: Deploy `landing` to Github Pages
-
-on:
- push:
- branches:
- - "main"
- paths:
- - "landing/**"
-
-jobs:
- build:
-
- runs-on: ubuntu-latest
-
- steps:
- - name: Checkout ποΈ
- uses: actions/checkout@v3
-
- - name: Use Node.js v16.x
- uses: actions/setup-node@v3
- with:
- node-version: 16.x
-
- - name: Install dependencies
- working-directory: ./landing
- run: |
- yarn install
-
- - name: Build and export Next.js site π§
- working-directory: ./landing
- run: |
- yarn build
- touch ./out/.nojekyll
-
- - name: Deploy π
- uses: JamesIves/github-pages-deploy-action@v4.3.3
- with:
- branch: gh-pages
- folder: ./landing/out
diff --git a/.github/workflows/test-docs-build.yml b/.github/workflows/test-docs-build.yml
new file mode 100644
index 00000000..d0e1b050
--- /dev/null
+++ b/.github/workflows/test-docs-build.yml
@@ -0,0 +1,33 @@
+name: Test docs build
+
+on:
+ pull_request:
+ branches:
+ - main
+ # Review gh actions docs if you want to further define triggers, paths, etc
+ # https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#on
+
+jobs:
+ test-deploy:
+ name: Test deployment
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v3
+
+ - name: Install Node.js
+ uses: actions/setup-node@v3
+ with:
+ node-version: 18
+
+ - uses: pnpm/action-setup@v2
+ name: Install pnpm
+ with:
+ version: 8
+ run_install: false
+
+ - name: Install dependencies
+ run: pnpm install
+
+ - name: Test build website
+ run: pnpm build
diff --git a/docs/.gitignore b/docs/.gitignore
new file mode 100644
index 00000000..6240da8b
--- /dev/null
+++ b/docs/.gitignore
@@ -0,0 +1,21 @@
+# build output
+dist/
+# generated types
+.astro/
+
+# dependencies
+node_modules/
+
+# logs
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+pnpm-debug.log*
+
+
+# environment variables
+.env
+.env.production
+
+# macOS-specific files
+.DS_Store
diff --git a/docs/README.md b/docs/README.md
new file mode 100644
index 00000000..37dfc32b
--- /dev/null
+++ b/docs/README.md
@@ -0,0 +1,51 @@
+# Starlight Starter Kit: Basics
+
+```
+npm create astro@latest -- --template starlight
+```
+
+[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/withastro/starlight/tree/main/examples/basics)
+[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/withastro/starlight/tree/main/examples/basics)
+
+> π§βπ **Seasoned astronaut?** Delete this file. Have fun!
+
+## π Project Structure
+
+Inside of your Astro + Starlight project, you'll see the following folders and files:
+
+```
+.
+βββ public/
+βββ src/
+β βββ assets/
+β βββ content/
+β β βββ docs/
+β β βββ config.ts
+β βββ env.d.ts
+βββ astro.config.mjs
+βββ package.json
+βββ tsconfig.json
+```
+
+Starlight looks for `.md` or `.mdx` files in the `src/content/docs/` directory. Each file is exposed as a route based on its file name.
+
+Images can be added to `src/assets/` and embedded in Markdown with a relative link.
+
+Static assets, like favicons, can be placed in the `public/` directory.
+
+## π§ Commands
+
+All commands are run from the root of the project, from a terminal:
+
+| Command | Action |
+| :------------------------ | :----------------------------------------------- |
+| `npm install` | Installs dependencies |
+| `npm run dev` | Starts local dev server at `localhost:4321` |
+| `npm run build` | Build your production site to `./dist/` |
+| `npm run preview` | Preview your build locally, before deploying |
+| `npm run astro ...` | Run CLI commands like `astro add`, `astro check` |
+| `npm run astro -- --help` | Get help using the Astro CLI |
+
+## π Want to learn more?
+
+Check out [Starlightβs docs](https://starlight.astro.build/), read [the Astro documentation](https://docs.astro.build), or jump into the [Astro Discord server](https://astro.build/chat).
diff --git a/docs/astro.config.mjs b/docs/astro.config.mjs
new file mode 100644
index 00000000..7f03b301
--- /dev/null
+++ b/docs/astro.config.mjs
@@ -0,0 +1,56 @@
+import { defineConfig } from 'astro/config'
+import starlight from '@astrojs/starlight'
+import { generateAPI } from 'starlight-openapi'
+// import overrideIntegration from './src/overrideIntegration.mjs'
+
+// Generate the documentation and get the associated sidebar groups.
+const { openAPISidebarGroups, starlightOpenAPI } = await generateAPI([
+ {
+ base: 'apis/resource-server',
+ label: 'Open Payments',
+ schema: '../openapi/resource-server.yaml'
+ },
+ {
+ base: 'apis/auth-server',
+ label: 'Open Payments Authorization Server',
+ schema: '../openapi/auth-server.yaml'
+ }
+])
+
+// https://astro.build/config
+export default defineConfig({
+ integrations: [
+ // overrideIntegration(),
+ starlight({
+ title: 'OpenPayments',
+ customCss: [
+ './node_modules/@interledger/docs-design-system/src/styles/green-theme.css',
+ './node_modules/@interledger/docs-design-system/src/styles/ilf-docs.css',
+ './src/styles/openpayments.css'
+ ],
+ logo: {
+ src: './public/favicon.svg'
+ },
+ sidebar: [
+ {
+ label: 'Documentation',
+ autogenerate: {
+ directory: 'introduction'
+ }
+ },
+ {
+ label: 'Security',
+ autogenerate: {
+ directory: 'security'
+ }
+ },
+ // Add the generated sidebar groups to the sidebar.
+ {
+ label: 'Specifications',
+ items: openAPISidebarGroups
+ }
+ ]
+ }),
+ starlightOpenAPI()
+ ]
+})
diff --git a/docs/package.json b/docs/package.json
new file mode 100644
index 00000000..820eff20
--- /dev/null
+++ b/docs/package.json
@@ -0,0 +1,20 @@
+{
+ "name": "openpayments-docs",
+ "type": "module",
+ "version": "0.0.1",
+ "scripts": {
+ "dev": "astro dev",
+ "start": "astro dev",
+ "build": "astro build",
+ "preview": "astro preview",
+ "astro": "astro"
+ },
+ "dependencies": {
+ "@astrojs/starlight": "0.6.1",
+ "@interledger/docs-design-system": "^0.0.12",
+ "astro": "2.10.12",
+ "sharp": "^0.32.6",
+ "shiki": "0.14.3",
+ "starlight-openapi": "^0.1.0"
+ }
+}
diff --git a/docs/public/favicon.svg b/docs/public/favicon.svg
new file mode 100644
index 00000000..2b0009c5
--- /dev/null
+++ b/docs/public/favicon.svg
@@ -0,0 +1 @@
+
diff --git a/docs/public/img/logo.svg b/docs/public/img/logo.svg
new file mode 100644
index 00000000..afbb3abe
--- /dev/null
+++ b/docs/public/img/logo.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/docs/src/api/auth-server.yaml b/docs/src/api/auth-server.yaml
new file mode 100644
index 00000000..f04009ee
--- /dev/null
+++ b/docs/src/api/auth-server.yaml
@@ -0,0 +1,540 @@
+openapi: 3.1.0
+info:
+ title: Open Payments Authorization Server
+ version: '1.1'
+ license:
+ name: Apache 2.0
+ identifier: Apache-2.0
+ summary: Open Payments Authorization Server
+ description: 'The Open Payments API is secured via [GNAP](https://datatracker.ietf.org/doc/html/draft-ietf-gnap-core-protocol). This specification describes the Open Payments Authorization Server API, which is an opinionated GNAP Server API.'
+ contact:
+ email: tech@interledger.org
+servers:
+ - url: 'https://openpayments.guide/auth'
+tags:
+ - name: grant
+ description: Grant operations
+ - name: token
+ description: Token operations
+paths:
+ /:
+ post:
+ summary: Grant Request
+ operationId: post-request
+ responses:
+ '200':
+ description: OK
+ content:
+ application/json:
+ schema:
+ oneOf:
+ - properties:
+ interact:
+ $ref: '#/components/schemas/interact-response'
+ continue:
+ $ref: '#/components/schemas/continue'
+ required:
+ - interact
+ - continue
+ - properties:
+ access_token:
+ $ref: '#/components/schemas/access_token'
+ continue:
+ $ref: '#/components/schemas/continue'
+ required:
+ - access_token
+ - continue
+ type: object
+ examples:
+ Interaction instructions:
+ value:
+ interact:
+ redirect: 'https://openpayments.guide/auth/4CF492MLVMSW9MKMXKHQ'
+ finish: 4105340a-05eb-4290-8739-f9e2b463bfa7
+ continue:
+ access_token:
+ value: 33OMUKMKSKU80UPRY5NM
+ uri: 'https://openpayments.guide/auth/continue/4CF492MLVMSW9MKMXKHQ'
+ wait: 30
+ Grant:
+ value:
+ access_token:
+ value: OS9M2PMHKUR64TB8N6BW7OZB8CDFONP219RP1LT0
+ manage: 'https://openpayments.guide/auth/token/dd17a202-9982-4ed9-ae31-564947fb6379'
+ expires_in: 3600
+ access:
+ - type: incoming-payment
+ actions:
+ - create
+ - read
+ identifier: 'https://openpayments.guide/bob'
+ continue:
+ access_token:
+ value: 33OMUKMKSKU80UPRY5NM
+ uri: 'https://openpayments.guide/auth/continue/4CF492MLVMSW9MKMXKHQ'
+ '400':
+ description: Bad Request
+ '401':
+ description: Unauthorized
+ '500':
+ description: Internal Server Error
+ requestBody:
+ content:
+ application/json:
+ schema:
+ description: ''
+ type: object
+ properties:
+ access_token:
+ type: object
+ required:
+ - access
+ properties:
+ access:
+ $ref: '#/components/schemas/access'
+ client:
+ $ref: '#/components/schemas/client'
+ interact:
+ $ref: '#/components/schemas/interact-request'
+ required:
+ - access_token
+ - client
+ examples:
+ Grant request for creating and reading recurring fixed payment:
+ value:
+ access_token:
+ access:
+ - type: outgoing-payment
+ actions:
+ - create
+ - read
+ identifier: 'https://openpayments.guide/alice'
+ limits:
+ receiver: 'https://openpayments.guide/connections/45a0d0ee-26dc-4c66-89e0-01fbf93156f7'
+ interval: 'R12/2019-08-24T14:15:22Z/P1M'
+ debitAmount:
+ value: '500'
+ assetCode: USD
+ assetScale: 2
+ client: 'https://webmonize.com/.well-known/pay'
+ interact:
+ start:
+ - redirect
+ finish:
+ method: redirect
+ uri: 'https://webmonize.com/return/876FGRD8VC'
+ nonce: 4edb2194-dbdf-46bb-9397-d5fd57b7c8a7
+ Grant request for creating and reading incoming payments:
+ value:
+ access_token:
+ access:
+ - type: incoming-payment
+ actions:
+ - create
+ - read
+ identifier: 'http://openpayments.guide/bob'
+ client: 'https://webmonize.com/.well-known/pay'
+ description: ''
+ description: Make a new grant request
+ security: []
+ tags:
+ - grant
+ parameters: []
+ '/continue/{id}':
+ parameters:
+ - schema:
+ type: string
+ name: id
+ in: path
+ required: true
+ post:
+ summary: Continuation Request
+ operationId: post-continue
+ responses:
+ '200':
+ description: Success
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ access_token:
+ $ref: '#/components/schemas/access_token'
+ continue:
+ $ref: '#/components/schemas/continue'
+ required:
+ - continue
+ examples:
+ Continuing After a Completed Interaction:
+ value:
+ access_token:
+ value: OS9M2PMHKUR64TB8N6BW7OZB8CDFONP219RP1LT0
+ manage: 'https://openpayments.guide/auth/token/dd17a202-9982-4ed9-ae31-564947fb6379'
+ expires_in: 3600
+ access:
+ - type: outgoing-payment
+ actions:
+ - create
+ - read
+ identifier: 'https://openpayments.guide/alice'
+ limits:
+ receiver: 'https://openpayments.guide/bob/incoming-payments/48884225-b393-4872-90de-1b737e2491c2'
+ interval: 'R12/2019-08-24T14:15:22Z/P1M'
+ debitAmount:
+ value: '500'
+ assetCode: USD
+ assetScale: 2
+ continue:
+ access_token:
+ value: 33OMUKMKSKU80UPRY5NM
+ uri: 'https://openpayments.guide/auth/continue/4CF492MLVMSW9MKMXKHQ'
+ wait: 30
+ Continuing During Pending Interaction:
+ value:
+ continue:
+ access_token:
+ value: 33OMUKMKSKU80UPRY5NM
+ uri: 'https://openpayments.guide/auth/continue/4CF492MLVMSW9MKMXKHQ'
+ wait: 30
+ '400':
+ description: Bad Request
+ '401':
+ description: Unauthorized
+ '404':
+ description: Not Found
+ requestBody:
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ interact_ref:
+ type: string
+ description: |-
+ The interaction reference generated for this
+ interaction by the AS.
+ required:
+ - interact_ref
+ examples:
+ Interaction Reference:
+ value:
+ interact_ref: ad82597c-bbfa-4eb0-b72e-328e005b8689
+ description: Continue a grant request during or after user interaction.
+ tags:
+ - grant
+ delete:
+ summary: Cancel Grant
+ operationId: delete-continue
+ responses:
+ '204':
+ description: No Content
+ '400':
+ description: Bad Request
+ '401':
+ description: Unauthorized
+ '404':
+ description: Not Found
+ description: Cancel a grant request or delete a grant client side.
+ tags:
+ - grant
+ '/token/{id}':
+ parameters:
+ - schema:
+ type: string
+ name: id
+ in: path
+ required: true
+ post:
+ summary: Rotate Access Token
+ operationId: post-token
+ responses:
+ '200':
+ description: OK
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ access_token:
+ $ref: '#/components/schemas/access_token'
+ required:
+ - access_token
+ examples:
+ New access token:
+ value:
+ access_token:
+ value: OZB8CDFONP219RP1LT0OS9M2PMHKUR64TB8N6BW7
+ manage: 'https://openpayments.guide/auth/token/8f69de01-5bf9-4603-91ed-eeca101081f1'
+ expires_in: 3600
+ access:
+ - type: outgoing-payment
+ actions:
+ - create
+ - read
+ identifier: 'https://openpayments.guide/alice'
+ limits:
+ interval: 'R12/2019-08-24T14:15:22Z/P1M'
+ receiver: 'https://openpayments.guide/bob/incoming-payments/48884225-b393-4872-90de-1b737e2491c2'
+ debitAmount:
+ value: '500'
+ assetCode: USD
+ assetScale: 2
+ '400':
+ description: Bad Request
+ '401':
+ description: Unauthorized
+ '404':
+ description: Not Found
+ description: Management endpoint to rotate access token.
+ tags:
+ - token
+ delete:
+ summary: Revoke Access Token
+ operationId: delete-token
+ description: Management endpoint to revoke access token.
+ responses:
+ '204':
+ description: No Content
+ '400':
+ description: Bad Request
+ '401':
+ description: Unauthorized
+ tags:
+ - token
+components:
+ schemas:
+ access:
+ type: array
+ description: A description of the rights associated with this access token.
+ items:
+ $ref: '#/components/schemas/access-item'
+ uniqueItems: true
+ maxItems: 3
+ access-item:
+ oneOf:
+ - $ref: '#/components/schemas/access-incoming'
+ - $ref: '#/components/schemas/access-outgoing'
+ - $ref: '#/components/schemas/access-quote'
+ description: The access associated with the access token is described using objects that each contain multiple dimensions of access.
+ unevaluatedProperties: false
+ access-incoming:
+ title: access-incoming
+ type: object
+ properties:
+ type:
+ type: string
+ enum: ['incoming-payment']
+ description: The type of resource request as a string. This field defines which other fields are allowed in the request object.
+ actions:
+ type: array
+ description: The types of actions the client instance will take at the RS as an array of strings.
+ items:
+ type: string
+ enum:
+ - create
+ - complete
+ - read
+ - read-all
+ - list
+ - list-all
+ uniqueItems: true
+ identifier:
+ type: string
+ format: uri
+ description: A string identifier indicating a specific resource at the RS.
+ required:
+ - type
+ - actions
+ access-outgoing:
+ title: access-outgoing
+ type: object
+ properties:
+ type:
+ type: string
+ enum: ['outgoing-payment']
+ description: The type of resource request as a string. This field defines which other fields are allowed in the request object.
+ actions:
+ type: array
+ description: The types of actions the client instance will take at the RS as an array of strings.
+ items:
+ type: string
+ enum:
+ - create
+ - read
+ - read-all
+ - list
+ - list-all
+ uniqueItems: true
+ identifier:
+ type: string
+ format: uri
+ description: A string identifier indicating a specific resource at the RS.
+ limits:
+ $ref: '#/components/schemas/limits-outgoing'
+ required:
+ - type
+ - actions
+ - identifier
+ access-quote:
+ title: access-quote
+ type: object
+ properties:
+ type:
+ type: string
+ enum: ['quote']
+ description: The type of resource request as a string. This field defines which other fields are allowed in the request object.
+ actions:
+ type: array
+ description: The types of actions the client instance will take at the RS as an array of strings.
+ items:
+ type: string
+ enum:
+ - create
+ - read
+ - read-all
+ uniqueItems: true
+ required:
+ - type
+ - actions
+ access_token:
+ title: access_token
+ type: object
+ description: A single access token or set of access tokens that the client instance can use to call the RS on behalf of the RO.
+ properties:
+ value:
+ type: string
+ description: The value of the access token as a string. The value is opaque to the client instance. The value SHOULD be limited to ASCII characters to facilitate transmission over HTTP headers within other protocols without requiring additional encoding.
+ manage:
+ type: string
+ format: uri
+ description: The management URI for this access token. This URI MUST NOT include the access token value and SHOULD be different for each access token issued in a request.
+ expires_in:
+ type: integer
+ description: The number of seconds in which the access will expire. The client instance MUST NOT use the access token past this time. An RS MUST NOT accept an access token past this time.
+ access:
+ $ref: '#/components/schemas/access'
+ required:
+ - value
+ - manage
+ - access
+ additionalProperties: false
+ client:
+ title: client
+ type: string
+ description: |-
+ Payment pointer of the client instance that is making this request.
+
+ When sending a non-continuation request to the AS, the client instance MUST identify itself by including the client field of the request and by signing the request.
+
+ A JSON Web Key Set document, including the public key that the client instance will use to protect this request and any continuation requests at the AS and any user-facing information about the client instance used in interactions, MUST be available at the payment pointer + `/jwks.json` url.
+
+ If sending a grant initiation request that requires RO interaction, the payment pointer MUST serve necessary client display information.
+ continue:
+ title: continue
+ type: object
+ description: 'If the AS determines that the request can be continued with additional requests, it responds with the continue field.'
+ properties:
+ access_token:
+ type: object
+ description: 'A unique access token for continuing the request, called the "continuation access token".'
+ required:
+ - value
+ properties:
+ value:
+ type: string
+ uri:
+ type: string
+ format: uri
+ description: The URI at which the client instance can make continuation requests.
+ wait:
+ type: integer
+ description: The amount of time in integer seconds the client instance MUST wait after receiving this request continuation response and calling the continuation URI.
+ required:
+ - access_token
+ - uri
+ interact-request:
+ title: interact
+ type: object
+ properties:
+ start:
+ type: array
+ description: Indicates how the client instance can start an interaction.
+ items:
+ type: string
+ enum:
+ - redirect
+ finish:
+ type: object
+ description: Indicates how the client instance can receive an indication that interaction has finished at the AS.
+ properties:
+ method:
+ type: string
+ enum:
+ - redirect
+ description: The callback method that the AS will use to contact the client instance.
+ uri:
+ type: string
+ format: uri
+ description: Indicates the URI that the AS will either send the RO to after interaction or send an HTTP POST request.
+ nonce:
+ type: string
+ description: 'Unique value to be used in the calculation of the "hash" query parameter sent to the callback URI, must be sufficiently random to be unguessable by an attacker. MUST be generated by the client instance as a unique value for this request.'
+ required:
+ - method
+ - uri
+ - nonce
+ required:
+ - start
+ description: The client instance declares the parameters for interaction methods that it can support using the interact field.
+ interact-response:
+ title: interact-response
+ type: object
+ properties:
+ redirect:
+ type: string
+ format: uri
+ description: The URI to direct the end user to.
+ finish:
+ type: string
+ description: Unique key to secure the callback.
+ required:
+ - redirect
+ - finish
+ interval:
+ title: Interval
+ type: string
+ description: '[ISO8601 repeating interval](https://en.wikipedia.org/wiki/ISO_8601#Repeating_intervals)'
+ examples:
+ - 'R11/2022-08-24T14:15:22Z/P1M'
+ - 'R/2017-03-01T13:00:00Z/2018-05-11T15:30:00Z'
+ - 'R-1/P1Y2M10DT2H30M/2022-05-11T15:30:00Z'
+ limits-outgoing:
+ title: limits-outgoing
+ description: Open Payments specific property that defines the limits under which outgoing payments can be created.
+ type: object
+ properties:
+ receiver:
+ $ref: './schemas.yaml#/components/schemas/receiver'
+ debitAmount:
+ description: 'All amounts are maxima, i.e. multiple payments can be created under a grant as long as the total amounts of these payments do not exceed the maximum amount per interval as specified in the grant.'
+ $ref: './schemas.yaml#/components/schemas/amount'
+ receiveAmount:
+ description: 'All amounts are maxima, i.e. multiple payments can be created under a grant as long as the total amounts of these payments do not exceed the maximum amount per interval as specified in the grant.'
+ $ref: './schemas.yaml#/components/schemas/amount'
+ interval:
+ $ref: '#/components/schemas/interval'
+ anyOf:
+ - not:
+ required:
+ - interval
+ - required:
+ - debitAmount
+ - required:
+ - receiveAmount
+ securitySchemes:
+ GNAP:
+ name: Authorization
+ type: apiKey
+ in: header
+security:
+ - GNAP: []
diff --git a/docs/src/api/resource-server.yaml b/docs/src/api/resource-server.yaml
new file mode 100644
index 00000000..fcfe71a0
--- /dev/null
+++ b/docs/src/api/resource-server.yaml
@@ -0,0 +1,1369 @@
+openapi: 3.1.0
+info:
+ title: Open Payments
+ version: '1.2'
+ license:
+ name: Apache 2.0
+ identifier: Apache-2.0
+ description: |-
+ The Open Payments API is a simple REST API with 5 resource types: **payment pointer**, **quote**, **connection**, **incoming payment** and **outgoing payment**.
+
+ The *service endpoint* for the API is always the URL of the payment pointer resource and all other resources (except connections) are sub-resources of the payment pointer.
+
+ An incoming payment defines meta data that is automatically attached to payments made into the payment pointer under that incoming payment. This facilitates automation of processes like reconciliation of payment into the payment pointer with external systems.
+
+ An outgoing payment is an instruction to make a payment out of the payment pointer.
+
+ 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 payment pointer. It is only valid for a limited time.
+
+ For privacy reasons a connection resource is not a sub-resource of a payment pointer.
+
+ All resource and collection resource representations use JSON and the media-type `application/json`.
+
+ The `payment pointer` 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: tech@interledger.org
+servers:
+ - url: '{paymentPointer}'
+ description: 'Server for when Payment Pointer has a pathname (ie https://openpayments.guide/alice)'
+ variables:
+ paymentPointer:
+ default: https://openpayments.guide/alice
+ - url: '{paymentPointer}/.well-known/pay'
+ description: 'Server for when Payment Pointer has no pathname (ie https://openpayments.guide)'
+ variables:
+ paymentPointer:
+ default: https://openpayments.guide
+tags:
+ - name: payment-pointer
+ description: payment pointer operations
+ - name: incoming-payment
+ description: incoming payment operations
+ - name: outgoing-payment
+ description: outgoing payment operations
+ - name: quote
+ description: quote operations
+ - name: stream-connection
+ description: interledger STREAM connections
+paths:
+ /:
+ get:
+ summary: Get a Payment Pointer
+ tags:
+ - payment-pointer
+ responses:
+ '200':
+ description: Payment Pointer Found
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/payment-pointer'
+ examples:
+ Get payment pointer for $openpayments.guide/alice:
+ value:
+ id: 'https://openpayments.guide/alice'
+ publicName: Alice
+ assetCode: USD
+ assetScale: 2
+ authServer: 'https://openpayments.guide/auth'
+ '404':
+ description: Payment Pointer Not Found
+ operationId: get-payment-pointer
+ description: |-
+ Retrieve the public information of the Payment Pointer.
+
+ This end-point should be open to anonymous requests as it allows clients to verify a Payment Pointer URL and get the basic information required to construct new transactions and discover the grant request URL.
+
+ The content should be slow changing and cacheable for long periods. Servers SHOULD use cache control headers.
+ security: []
+ x-internal: false
+ /jwks.json:
+ get:
+ summary: Get the keys bound to a Payment Pointer
+ tags:
+ - payment-pointer
+ responses:
+ '200':
+ description: JWKS Document Found
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/json-web-key-set'
+ examples: {}
+ '404':
+ description: JWKS Document Not Found
+ operationId: get-payment-pointer-keys
+ description: Retrieve the public keys of the Payment Pointer.
+ security: []
+ '/connections/{id}':
+ servers:
+ - url: 'https://openpayments.guide'
+ get:
+ summary: Get ILP STREAM credentials for a connection
+ tags:
+ - stream-connection
+ responses:
+ '200':
+ description: Connection Found
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ilp-stream-connection'
+ examples:
+ Get connection:
+ value:
+ id: 'https://openpayments.guide/connections/016da9d5-c9a4-4c80-a354-86b915a04ff8'
+ ilpAddress: g.ilp.iwuyge987y.98y0f34tsrt8y
+ sharedSecret: 1c7eaXa4rd2fFOBl1iydvCT1tV5TbM3RW1WLCafu_JA
+ assetCode: USD
+ assetScale: 2
+ '404':
+ description: Connection Not Found
+ operationId: get-ilp-stream-connection
+ description: |-
+ *NB* Use server url specific to this path.
+
+ Fetch new connection credentials for an ILP STREAM connection.
+
+ A connection is an ephemeral resource that is created to accommodate new incoming payments.
+
+ A new set of credential will be generated each time this API is called.
+ security: []
+ parameters:
+ - $ref: '#/components/parameters/id'
+ /incoming-payments:
+ post:
+ summary: Create an Incoming Payment
+ tags:
+ - incoming-payment
+ operationId: create-incoming-payment
+ responses:
+ '201':
+ description: Incoming Payment Created
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/incoming-payment-with-connection'
+ examples:
+ New Incoming Payment for $25:
+ value:
+ id: 'https://openpayments.guide/alice/incoming-payments/08394f02-7b7b-45e2-b645-51d04e7c330c'
+ paymentPointer: 'https://openpayments.guide/alice/'
+ incomingAmount:
+ value: '2500'
+ assetCode: USD
+ assetScale: 2
+ receivedAmount:
+ value: '0'
+ assetCode: USD
+ assetScale: 2
+ completed: false
+ expiresAt: '2022-02-03T23:20:50.52Z'
+ metadata:
+ externalRef: INV2022-02-0137
+ ilpStreamConnection:
+ id: 'https://openpayments.guide/connections/ff394f02-7b7b-45e2-b645-51d04e7c345c'
+ ilpAddress: g.ilp.iwuyge987y.98y08y
+ sharedSecret: 1c7eaXa4rd2fFOBl1iydvCT1tV5TbM3RW1WLCafu_JA
+ assetCode: USD
+ assetScale: 2
+ createdAt: '2022-03-12T23:20:50.52Z'
+ updatedAt: '2022-04-01T10:24:36.11Z'
+ '401':
+ $ref: '#/components/responses/401'
+ '403':
+ $ref: '#/components/responses/403'
+ requestBody:
+ content:
+ application/json:
+ schema:
+ type: object
+ additionalProperties: false
+ properties:
+ incomingAmount:
+ $ref: ./schemas.yaml#/components/schemas/amount
+ description: The maximum amount that should be paid into the payment pointer under this incoming payment.
+ expiresAt:
+ type: string
+ description: The date and time when payments into the incoming payment must no longer be accepted.
+ format: date-time
+ writeOnly: true
+ metadata:
+ type: object
+ description: Additional metadata associated with the incoming payment. (Optional)
+ examples:
+ Create incoming payment for $25 to pay invoice INV2022-02-0137:
+ value:
+ incomingAmount:
+ value: '2500'
+ assetCode: USD
+ assetScale: 2
+ metadata:
+ externalRef: INV2022-02-0137
+ description: |-
+ A subset of the incoming payments schema is accepted as input to create a new incoming payment.
+
+ The `incomingAmount` must use the same `assetCode` and `assetScale` as the payment pointer.
+ required: true
+ description: |-
+ A client MUST create an **incoming payment** resource before it is possible to send any payments to the payment pointer.
+
+ When a client creates an **incoming payment** the receiving Account Servicing Entity generates unique payment details that can be used to address payments to the account and returns these details to the client as properties of the new **incoming payment**. Any payments received using those details are then associated with the **incoming payment**.
+
+ All of the input parameters are _optional_.
+
+ For example, the client could use the `metadata` property to store an external reference on the **incoming payment** and this can be shared with the account holder to assist with reconciliation.
+
+ If `incomingAmount` is specified and the total received using the payment details equals or exceeds the specified `incomingAmount`, then the receiving Account Servicing Entity MUST reject any further payments and set `completed` to `true`.
+
+ If an `expiresAt` value is defined, and the current date and time on the receiving Account Servicing Entity's systems exceeds that value, the receiving Account Servicing Entity MUST reject any further payments.
+ parameters:
+ - $ref: '#/components/parameters/signature-input'
+ - $ref: '#/components/parameters/signature'
+ get:
+ summary: List Incoming Payments
+ operationId: list-incoming-payments
+ responses:
+ '200':
+ description: OK
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ pagination:
+ $ref: '#/components/schemas/page-info'
+ result:
+ type: array
+ items:
+ $ref: '#/components/schemas/incoming-payment-with-connection-url'
+ examples:
+ forward pagination:
+ value:
+ pagination:
+ startCursor: 241de237-f989-42be-926d-c0c1fca57708
+ endCursor: 315581f8-9967-45a0-9cd3-87b60b6d6414
+ hasPreviousPage: false
+ hasNextPage: true
+ result:
+ - id: 'https://openpayments.guide/alice/incoming-payments/016da9d5-c9a4-4c80-a354-86b915a04ff8'
+ paymentPointer: 'https://openpayments.guide/alice/'
+ incomingAmount:
+ value: '250'
+ assetCode: USD
+ assetScale: 2
+ receivedAmount:
+ value: '250'
+ assetCode: USD
+ assetScale: 2
+ ilpStreamConnection: 'https://openpayments.guide/connections/376df9d5-c9a4-4c80-a354-86b915a04ff8'
+ expiresAt: '2022-04-12T23:20:50.52Z'
+ createdAt: '2022-03-12T23:20:50.52Z'
+ updatedAt: '2022-04-01T10:24:36.11Z'
+ metadata:
+ description: 'Hi Mo, this is for the cappuccino I bought for you the other day.'
+ externalRef: Coffee w/ Mo on 10 March 22
+ completed: true
+ - id: 'https://openpayments.guide/alice/incoming-payments/32abc219-3dc3-44ec-a225-790cacfca8fa'
+ paymentPointer: 'https://openpayments.guide/alice/'
+ receivedAmount:
+ value: '100'
+ assetCode: USD
+ assetScale: 2
+ ilpStreamConnection: 'https://openpayments.guide/connections/1f6df9d5-c9a4-4c80-a354-86b915a04ff8'
+ expiresAt: '2022-04-12T23:20:50.52Z'
+ createdAt: '2022-03-12T23:20:50.52Z'
+ updatedAt: '2022-04-01T10:24:36.11Z'
+ metadata:
+ description: 'I love your website, Alice! Thanks for the great content'
+ completed: false
+ backward pagination:
+ value:
+ pagination:
+ startCursor: 241de237-f989-42be-926d-c0c1fca57708
+ endCursor: 315581f8-9967-45a0-9cd3-87b60b6d6414
+ hasPreviousPage: true
+ hasNextPage: false
+ result:
+ - id: 'https://openpayments.guide/alice/incoming-payments/32abc219-3dc3-44ec-a225-790cacfca8fa'
+ paymentPointer: 'https://openpayments.guide/alice/'
+ receivedAmount:
+ value: '100'
+ assetCode: USD
+ assetScale: 2
+ completed: true
+ ilpStreamConnection: 'https://openpayments.guide/connections/1f6df9d5-c9a4-4c80-a354-86b915a04ff8'
+ expiresAt: '2022-04-12T23:20:50.52Z'
+ createdAt: '2022-03-12T23:20:50.52Z'
+ updatedAt: '2022-04-01T10:24:36.11Z'
+ metadata:
+ description: 'I love your website, Alice! Thanks for the great content'
+ - id: 'https://openpayments.guide/alice/incoming-payments/016da9d5-c9a4-4c80-a354-86b915a04ff8'
+ paymentPointer: 'https://openpayments.guide/alice/'
+ incomingAmount:
+ value: '250'
+ assetCode: USD
+ assetScale: 2
+ receivedAmount:
+ value: '250'
+ assetCode: USD
+ assetScale: 2
+ completed: true
+ ilpStreamConnection: 'https://openpayments.guide/connections/376df9d5-c9a4-4c80-a354-86b915a04ff8'
+ expiresAt: '2022-04-12T23:20:50.52Z'
+ createdAt: '2022-03-12T23:20:50.52Z'
+ updatedAt: '2022-04-01T10:24:36.11Z'
+ metadata:
+ description: 'Hi Mo, this is for the cappuccino I bought for you the other day.'
+ externalRef: Coffee w/ Mo on 10 March 22
+ '401':
+ $ref: '#/components/responses/401'
+ '403':
+ $ref: '#/components/responses/403'
+ description: List all incoming payments on the payment pointer
+ parameters:
+ - $ref: '#/components/parameters/cursor'
+ - $ref: '#/components/parameters/first'
+ - $ref: '#/components/parameters/last'
+ - $ref: '#/components/parameters/signature-input'
+ - $ref: '#/components/parameters/signature'
+ tags:
+ - incoming-payment
+ /outgoing-payments:
+ post:
+ summary: Create an Outgoing Payment
+ tags:
+ - outgoing-payment
+ operationId: create-outgoing-payment
+ responses:
+ '201':
+ description: Outgoing Payment Created
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/outgoing-payment'
+ examples:
+ New Fixed Send Outgoing Payment for $25:
+ value:
+ id: 'https://openpayments.guide/alice/outgoing-payments/8c68d3cc-0a0f-4216-98b4-4fa44a6c88cf'
+ paymentPointer: 'https://openpayments.guide/alice/'
+ failed: false
+ receiver: 'https://openpayments.guide/bob/incoming-payments/48884225-b393-4872-90de-1b737e2491c2'
+ debitAmount:
+ value: '2600'
+ assetCode: USD
+ assetScale: 2
+ receiveAmount:
+ value: '2500'
+ assetCode: USD
+ assetScale: 2
+ sentAmount:
+ value: '0'
+ assetCode: USD
+ assetScale: 2
+ metadata:
+ description: Thank you for the shoes.
+ createdAt: '2022-03-12T23:20:50.52Z'
+ updatedAt: '2022-04-01T10:24:36.11Z'
+ '401':
+ $ref: '#/components/responses/401'
+ '403':
+ $ref: '#/components/responses/403'
+ requestBody:
+ content:
+ application/json:
+ examples:
+ Create an outgoing payment based on a quote:
+ value:
+ quoteId: 'https://openpayments.guide/alice/quotes/ab03296b-0c8b-4776-b94e-7ee27d868d4d'
+ metadata:
+ externalRef: INV2022-02-0137
+ schema:
+ type: object
+ properties:
+ quoteId:
+ type: string
+ format: uri
+ description: The URL of the quote defining this payment's amounts.
+ metadata:
+ type: object
+ additionalProperties: true
+ description: Additional metadata associated with the outgoing payment. (Optional)
+ required:
+ - quoteId
+ additionalProperties: false
+ description: |-
+ A subset of the outgoing payments schema is accepted as input to create a new outgoing payment.
+
+ The `debitAmount` must use the same `assetCode` and `assetScale` as the payment pointer.
+ required: true
+ description: |-
+ An **outgoing payment** is a sub-resource of a payment pointer. It represents a payment from the payment pointer.
+
+ Once created, it is already authorized and SHOULD be processed immediately. If payment fails, the Account Servicing Entity must mark the **outgoing payment** as `failed`.
+ parameters:
+ - $ref: '#/components/parameters/signature-input'
+ - $ref: '#/components/parameters/signature'
+ description: Create a new outgoing payment at the payment pointer.
+ get:
+ summary: List Outgoing Payments
+ operationId: list-outgoing-payments
+ responses:
+ '200':
+ description: OK
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ pagination:
+ $ref: '#/components/schemas/page-info'
+ result:
+ type: array
+ items:
+ $ref: '#/components/schemas/outgoing-payment'
+ examples:
+ forward pagination:
+ value:
+ pagination:
+ startCursor: 241de237-f989-42be-926d-c0c1fca57708
+ endCursor: 315581f8-9967-45a0-9cd3-87b60b6d6414
+ hasPreviousPage: false
+ hasNextPage: true
+ result:
+ - id: 'https://openpayments.guide/alice/outgoing-payments/8c68d3cc-0a0f-4216-98b4-4fa44a6c88cf'
+ paymentPointer: 'https://openpayments.guide/alice/'
+ failed: false
+ receiver: 'https://openpayments.guide/aplusvideo/incoming-payments/45d495ad-b763-4882-88d7-aa14d261686e'
+ receiveAmount:
+ value: '2500'
+ assetCode: USD
+ assetScale: 2
+ debitAmount:
+ value: '2600'
+ assetCode: USD
+ assetScale: 2
+ sentAmount:
+ value: '2500'
+ assetCode: USD
+ assetScale: 2
+ createdAt: '2022-03-12T23:20:50.52Z'
+ updatedAt: '2022-04-01T10:24:36.11Z'
+ metadata:
+ description: APlusVideo subscription
+ externalRef: 'customer: 847458475'
+ - id: 'https://openpayments.guide/alice/outgoing-payments/0cffa5a4-58fd-4cc8-8e01-7145c72bf07c'
+ paymentPointer: 'https://openpayments.guide/alice/'
+ failed: false
+ receiver: 'https://openpayments.guide/shoeshop/incoming-payments/2fe92c6f-ef0d-487c-8759-3784eae6bce9'
+ debitAmount:
+ value: '7126'
+ assetCode: USD
+ assetScale: 2
+ receiveAmount:
+ value: '7026'
+ assetCode: USD
+ assetScale: 2
+ sentAmount:
+ value: '7026'
+ assetCode: USD
+ assetScale: 2
+ createdAt: '2022-03-12T23:20:50.52Z'
+ updatedAt: '2022-04-01T10:24:36.11Z'
+ metadata:
+ description: Thank you for your purchase at ShoeShop!
+ externalRef: INV2022-8943756
+ backward pagination:
+ value:
+ pagination:
+ startCursor: 241de237-f989-42be-926d-c0c1fca57708
+ endCursor: 315581f8-9967-45a0-9cd3-87b60b6d6414
+ hasPreviousPage: true
+ hasNextPage: false
+ result:
+ - id: 'https://openpayments.guide/alice/outgoing-payments/0cffa5a4-58fd-4cc8-8e01-7145c72bf07c'
+ paymentPointer: 'https://openpayments.guide/alice/'
+ failed: false
+ receiver: 'https://openpayments.guide/shoeshop/incoming-payments/2fe92c6f-ef0d-487c-8759-3784eae6bce9'
+ debitAmount:
+ value: '7126'
+ assetCode: USD
+ assetScale: 2
+ receiveAmount:
+ value: '7026'
+ assetCode: USD
+ assetScale: 2
+ sentAmount:
+ value: '7026'
+ assetCode: USD
+ assetScale: 2
+ createdAt: '2022-03-12T23:20:50.52Z'
+ updatedAt: '2022-04-01T10:24:36.11Z'
+ metadata:
+ description: Thank you for your purchase at ShoeShop!
+ externalRef: INV2022-8943756
+ - id: 'https://openpayments.guide/alice/outgoing-payments/8c68d3cc-0a0f-4216-98b4-4fa44a6c88cf'
+ paymentPointer: 'https://openpayments.guide/alice/'
+ failed: false
+ receiver: 'https://openpayments.guide/aplusvideo/incoming-payments/45d495ad-b763-4882-88d7-aa14d261686e'
+ receiveAmount:
+ value: '2500'
+ assetCode: USD
+ assetScale: 2
+ debitAmount:
+ value: '2600'
+ assetCode: USD
+ assetScale: 2
+ sentAmount:
+ value: '2500'
+ assetCode: USD
+ assetScale: 2
+ createdAt: '2022-03-12T23:20:50.52Z'
+ updatedAt: '2022-04-01T10:24:36.11Z'
+ metadata:
+ description: APlusVideo subscription
+ externalRef: 'customer: 847458475'
+ '401':
+ $ref: '#/components/responses/401'
+ '403':
+ $ref: '#/components/responses/403'
+ description: List all outgoing payments on the payment pointer
+ parameters:
+ - $ref: '#/components/parameters/cursor'
+ - $ref: '#/components/parameters/first'
+ - $ref: '#/components/parameters/last'
+ - $ref: '#/components/parameters/signature-input'
+ - $ref: '#/components/parameters/signature'
+ tags:
+ - outgoing-payment
+ /quotes:
+ post:
+ summary: Create a Quote
+ tags:
+ - quote
+ operationId: create-quote
+ responses:
+ '201':
+ description: Quote Created
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/quote'
+ examples:
+ New Fixed Send Quote for $25:
+ value:
+ id: 'https://openpayments.guide/alice/quotes/8c68d3cc-0a0f-4216-98b4-4fa44a6c88cf'
+ paymentPointer: 'https://openpayments.guide/alice/'
+ receiver: 'https://openpayments.guide/aplusvideo/incoming-payments/45d495ad-b763-4882-88d7-aa14d261686e'
+ debitAmount:
+ value: '2500'
+ assetCode: USD
+ assetScale: 2
+ receiveAmount:
+ value: '2198'
+ assetCode: EUR
+ assetScale: 2
+ createdAt: '2022-03-12T23:20:50.52Z'
+ expiresAt: '2022-04-12T23:20:50.52Z'
+ '400':
+ description: No amount was provided and no amount could be inferred from the receiver.
+ '401':
+ $ref: '#/components/responses/401'
+ '403':
+ $ref: '#/components/responses/403'
+ requestBody:
+ content:
+ application/json:
+ examples:
+ Create fixed-send-amount quote for $25 to an ILP STREAM connection:
+ value:
+ receiver: 'https://openpayments.guide/connections/45a0d0ee-26dc-4c66-89e0-01fbf93156f7'
+ debitAmount:
+ value: '2500'
+ assetCode: USD
+ assetScale: 2
+ Create fixed-receive-amount quote for $25:
+ value:
+ receiver: 'https://openpayments.guide/alice/incoming-payments/37a0d0ee-26dc-4c66-89e0-01fbf93156f7'
+ receiveAmount:
+ value: '2500'
+ assetCode: USD
+ assetScale: 2
+ schema:
+ oneOf:
+ - description: Create quote for an `receiver` that is an Incoming Payment with an `incomingAmount`
+ properties:
+ receiver:
+ $ref: ./schemas.yaml#/components/schemas/receiver
+ required:
+ - receiver
+ additionalProperties: false
+ - description: Create a quote with a fixed-receive amount
+ properties:
+ receiver:
+ $ref: ./schemas.yaml#/components/schemas/receiver
+ receiveAmount:
+ description: The fixed amount that would be paid into the receiving payment pointer given a successful outgoing payment.
+ $ref: ./schemas.yaml#/components/schemas/amount
+ required:
+ - receiver
+ - receiveAmount
+ additionalProperties: false
+ - description: Create a quote with a fixed send amount
+ properties:
+ receiver:
+ $ref: ./schemas.yaml#/components/schemas/receiver
+ debitAmount:
+ description: The fixed amount that would be sent from the sending payment pointer given a successful outgoing payment.
+ $ref: ./schemas.yaml#/components/schemas/amount
+ required:
+ - receiver
+ - debitAmount
+ additionalProperties: false
+ description: |-
+ A subset of the quotes schema is accepted as input to create a new quote.
+
+ The quote must be created with a (`debitAmount` xor `receiveAmount`) unless the `receiver` is an Incoming Payment which has an `incomingAmount`.
+ required: true
+ description: A **quote** is a sub-resource of a payment pointer. It represents a quote for a payment from the payment pointer.
+ parameters:
+ - $ref: '#/components/parameters/signature-input'
+ - $ref: '#/components/parameters/signature'
+ description: Create a new quote at the payment pointer.
+ '/incoming-payments/{id}':
+ get:
+ summary: Get an Incoming Payment
+ tags:
+ - incoming-payment
+ operationId: get-incoming-payment
+ responses:
+ '200':
+ description: Incoming Payment Found
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/incoming-payment-with-connection'
+ examples:
+ Incoming Payment for $25 with $12.34 received so far:
+ value:
+ id: 'https://openpayments.guide/alice/incoming-payments/2f1b0150-db73-49e8-8713-628baa4a17ff'
+ paymentPointer: 'https://openpayments.guide/alice/'
+ incomingAmount:
+ value: '2500'
+ assetCode: USD
+ assetScale: 2
+ receivedAmount:
+ value: '1234'
+ assetCode: USD
+ assetScale: 2
+ completed: false
+ expiresAt: '2022-04-12T23:20:50.52Z'
+ createdAt: '2022-03-12T23:20:50.52Z'
+ updatedAt: '2022-04-01T10:24:36.11Z'
+ metadata:
+ description: Thanks for the flowers!
+ externalRef: INV-12876
+ ilpStreamConnection:
+ id: 'https://openpayments.guide/connections/4a1b0150-db73-49e8-8713-628baa4a17ff'
+ ilpAddress: g.ilp.iwuyge987y.98y08y
+ sharedSecret: 1c7eaXa4rd2fFOBl1iydvCT1tV5TbM3RW1WLCafu_JA
+ assetCode: USD
+ assetScale: 2
+ '401':
+ $ref: '#/components/responses/401'
+ '403':
+ $ref: '#/components/responses/403'
+ '404':
+ description: Incoming Payment Not Found
+ description: A client can fetch the latest state of an incoming payment to determine the amount received into the payment pointer.
+ parameters:
+ - $ref: '#/components/parameters/signature-input'
+ - $ref: '#/components/parameters/signature'
+ parameters:
+ - $ref: '#/components/parameters/id'
+ '/incoming-payments/{id}/complete':
+ post:
+ summary: Complete an Incoming Payment
+ tags:
+ - incoming-payment
+ operationId: complete-incoming-payment
+ responses:
+ '200':
+ description: OK
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/incoming-payment'
+ additionalProperties: false
+ examples:
+ Completed Incoming Payment:
+ value:
+ id: 'https://openpayments.guide/alice/incoming-payments/016da9d5-c9a4-4c80-a354-86b915a04ff8'
+ paymentPointer: 'https://openpayments.guide/alice/'
+ incomingAmount:
+ value: '250'
+ assetCode: USD
+ assetScale: 2
+ receivedAmount:
+ value: '250'
+ assetCode: USD
+ assetScale: 2
+ completed: true
+ expiresAt: '2022-04-12T23:20:50.52Z'
+ createdAt: '2022-03-12T23:20:50.52Z'
+ updatedAt: '2022-04-01T10:24:36.11Z'
+ metadata:
+ description: 'Hi Mo, this is for the cappuccino I bought for you the other day.'
+ externalRef: Coffee w/ Mo on 10 March 2
+ '401':
+ $ref: '#/components/responses/401'
+ '403':
+ $ref: '#/components/responses/403'
+ '404':
+ description: Incoming Payment Not Found
+ description: |-
+ A client with the appropriate permissions MAY mark a non-expired **incoming payment** as `completed` indicating that the client is not going to make any further payments toward this **incoming payment**, even though the full `incomingAmount` may not have been received.
+
+ This indicates to the receiving Account Servicing Entity that it can begin any post processing of the payment such as generating account statements or notifying the account holder of the completed payment.
+ parameters:
+ - $ref: '#/components/parameters/signature-input'
+ - $ref: '#/components/parameters/signature'
+ parameters:
+ - $ref: '#/components/parameters/id'
+ '/outgoing-payments/{id}':
+ get:
+ summary: Get an Outgoing Payment
+ tags:
+ - outgoing-payment
+ operationId: get-outgoing-payment
+ responses:
+ '200':
+ description: Outgoing Payment Found
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/outgoing-payment'
+ examples:
+ Outgoing Payment with a fixed send amount of $25:
+ value:
+ id: 'https://openpayments.guide/bob/outgoing-payments/3859b39e-4666-4ce5-8745-72f1864c5371'
+ paymentPointer: 'https://openpayments.guide/bob/'
+ failed: false
+ receiver: 'https://openpayments.guide/alice/incoming-payments/2f1b0150-db73-49e8-8713-628baa4a17ff'
+ debitAmount:
+ value: '2500'
+ assetCode: USD
+ assetScale: 2
+ receiveAmount:
+ value: '2198'
+ assetCode: EUR
+ assetScale: 2
+ sentAmount:
+ value: '1205'
+ assetCode: USD
+ assetScale: 2
+ createdAt: '2022-03-12T23:20:50.52Z'
+ updatedAt: '2022-04-01T10:24:36.11Z'
+ metadata:
+ description: Thanks for the flowers!
+ externalRef: INV-12876
+ '401':
+ $ref: '#/components/responses/401'
+ '403':
+ $ref: '#/components/responses/403'
+ '404':
+ description: Outgoing Payment Not Found
+ description: A client can fetch the latest state of an outgoing payment.
+ parameters:
+ - $ref: '#/components/parameters/signature-input'
+ - $ref: '#/components/parameters/signature'
+ parameters:
+ - $ref: '#/components/parameters/id'
+ '/quotes/{id}':
+ get:
+ summary: Get a Quote
+ tags:
+ - quote
+ operationId: get-quote
+ responses:
+ '200':
+ description: Quote Found
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/quote'
+ examples:
+ Quote with a fixed send amount of $25:
+ value:
+ id: 'https://openpayments.guide/bob/quotes/3859b39e-4666-4ce5-8745-72f1864c5371'
+ paymentPointer: 'https://openpayments.guide/bob/'
+ receiver: 'https://openpayments.guide/alice/incoming-payments/2f1b0150-db73-49e8-8713-628baa4a17ff'
+ debitAmount:
+ value: '2500'
+ assetCode: USD
+ assetScale: 2
+ receiveAmount:
+ value: '2198'
+ assetCode: EUR
+ assetScale: 2
+ createdAt: '2022-03-12T23:20:50.52Z'
+ expiresAt: '2022-04-12T23:20:50.52Z'
+ '401':
+ $ref: '#/components/responses/401'
+ '403':
+ $ref: '#/components/responses/403'
+ '404':
+ description: Quote Not Found
+ description: A client can fetch the latest state of a quote.
+ parameters:
+ - $ref: '#/components/parameters/signature-input'
+ - $ref: '#/components/parameters/signature'
+ parameters:
+ - $ref: '#/components/parameters/id'
+components:
+ schemas:
+ payment-pointer:
+ title: Payment Pointer
+ type: object
+ description: A **payment pointer** resource is the root of the API and contains the public details of the financial account represented by the Payment Pointer that is also the service endpoint URL.
+ additionalProperties: false
+ examples:
+ - id: 'https://openpayments.guide/alice'
+ publicName: Alice
+ assetCode: USD
+ assetScale: 2
+ authServer: 'https://openpayments.guide/auth'
+ properties:
+ id:
+ type: string
+ format: uri
+ description: The URL identifying the payment pointer.
+ readOnly: true
+ publicName:
+ type: string
+ description: A public name for the account. This should be set by the account holder with their provider to provide a hint to counterparties as to the identity of the account holder.
+ readOnly: true
+ assetCode:
+ $ref: ./schemas.yaml#/components/schemas/assetCode
+ assetScale:
+ $ref: ./schemas.yaml#/components/schemas/assetScale
+ authServer:
+ type: string
+ format: uri
+ description: The URL of the authorization server endpoint for getting grants and access tokens for this payment pointer.
+ readOnly: true
+ required:
+ - id
+ - assetCode
+ - assetScale
+ - authServer
+ json-web-key-set:
+ title: JSON Web Key Set document
+ type: object
+ description: 'A JSON Web Key Set document according to [rfc7517](https://datatracker.ietf.org/doc/html/rfc7517) listing the keys associated with this payment pointer. These keys are used to sign requests made by this payment pointer.'
+ additionalProperties: false
+ properties:
+ keys:
+ type: array
+ items:
+ $ref: '#/components/schemas/json-web-key'
+ readOnly: true
+ required:
+ - keys
+ examples:
+ - keys:
+ - kid: key-1
+ alg: EdDSA
+ use: sig
+ kty: OKP
+ crv: Ed25519
+ x: 11qYAYKxCrfVS_7TyWQHOg7hcvPapiMlrwIaaPcHURo
+ ilp-stream-connection:
+ title: ILP Stream Connection
+ type: object
+ description: An **ILP STREAM Connection** is an endpoint that returns unique STREAM connection credentials to establish a STREAM connection to the underlying account.
+ additionalProperties: false
+ examples:
+ - id: 'https://openpayments.guide/connections/016da9d5-c9a4-4c80-a354-86b915a04ff8'
+ ilpApddress: g.ilp.iwuyge987y.98y08y
+ sharedSecret: 1c7eaXa4rd2fFOBl1iydvCT1tV5TbM3RW1WLCafu_JA
+ properties:
+ id:
+ type: string
+ format: uri
+ description: The URL identifying the endpoint.
+ readOnly: true
+ 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.
+ readOnly: true
+ sharedSecret:
+ type: string
+ pattern: '^[a-zA-Z0-9-_]+$'
+ description: The base64 url-encoded shared secret to use when establishing a STREAM connection.
+ readOnly: true
+ assetCode:
+ $ref: ./schemas.yaml#/components/schemas/assetCode
+ assetScale:
+ $ref: ./schemas.yaml#/components/schemas/assetScale
+ required:
+ - id
+ - ilpAddress
+ - sharedSecret
+ - assetCode
+ - assetScale
+ incoming-payment:
+ title: Incoming Payment
+ description: 'An **incoming payment** resource represents a payment that will be, is currently being, or has been received by the account.'
+ type: object
+ examples:
+ - id: 'https://openpayments.guide/alice/incoming-payments/016da9d5-c9a4-4c80-a354-86b915a04ff8'
+ paymentPointer: 'https://openpayments.guide/alice/'
+ incomingAmount:
+ value: '250'
+ assetCode: USD
+ assetScale: 2
+ receivedAmount:
+ value: '250'
+ assetCode: USD
+ assetScale: 2
+ completed: true
+ expiresAt: '2022-04-12T23:20:50.52Z'
+ createdAt: '2022-03-12T23:20:50.52Z'
+ updatedAt: '2022-04-01T10:24:36.11Z'
+ metadata:
+ description: 'Hi Mo, this is for the cappuccino I bought for you the other day.'
+ externalRef: Coffee w/ Mo on 10 March 22
+ - id: 'https://openpayments.guide/alice/incoming-payments/456da9d5-c9a4-4c80-a354-86b915a04ff8'
+ paymentPointer: 'https://openpayments.guide/alice/'
+ incomingAmount:
+ value: '2500'
+ assetCode: USD
+ assetScale: 2
+ receivedAmount:
+ value: '0'
+ assetCode: USD
+ assetScale: 2
+ expiresAt: '2022-04-12T23:20:50.52Z'
+ createdAt: '2022-03-12T23:20:50.52Z'
+ updatedAt: '2022-03-12T23:20:50.52Z'
+ properties:
+ id:
+ type: string
+ format: uri
+ description: The URL identifying the incoming payment.
+ readOnly: true
+ paymentPointer:
+ type: string
+ format: uri
+ description: The URL of the payment pointer this payment is being made into.
+ readOnly: true
+ completed:
+ type: boolean
+ description: Describes whether the incoming payment has completed receiving fund.
+ default: false
+ incomingAmount:
+ $ref: ./schemas.yaml#/components/schemas/amount
+ description: The maximum amount that should be paid into the payment pointer under this incoming payment.
+ receivedAmount:
+ $ref: ./schemas.yaml#/components/schemas/amount
+ description: The total amount that has been paid into the payment pointer under this incoming payment.
+ expiresAt:
+ type: string
+ description: The date and time when payments under this incoming payment will no longer be accepted.
+ format: date-time
+ metadata:
+ type: object
+ description: Additional metadata associated with the incoming payment. (Optional)
+ createdAt:
+ type: string
+ format: date-time
+ description: The date and time when the incoming payment was created.
+ updatedAt:
+ type: string
+ format: date-time
+ description: The date and time when the incoming payment was updated.
+ required:
+ - id
+ - paymentPointer
+ - completed
+ - receivedAmount
+ - createdAt
+ - updatedAt
+ incoming-payment-with-connection:
+ title: Incoming Payment with Connection
+ description: An **incoming payment** resource with the Interledger STREAM Connection to use to pay into the payment pointer under this incoming payment.
+ type: object
+ examples:
+ - id: 'https://openpayments.guide/alice/incoming-payments/016da9d5-c9a4-4c80-a354-86b915a04ff8'
+ paymentPointer: 'https://openpayments.guide/alice/'
+ incomingAmount:
+ value: '250'
+ assetCode: USD
+ assetScale: 2
+ receivedAmount:
+ value: '250'
+ assetCode: USD
+ assetScale: 2
+ completed: true
+ expiresAt: '2022-04-12T23:20:50.52Z'
+ createdAt: '2022-03-12T23:20:50.52Z'
+ updatedAt: '2022-04-01T10:24:36.11Z'
+ metadata:
+ description: 'Hi Mo, this is for the cappuccino I bought for you the other day.'
+ externalRef: Coffee w/ Mo on 10 March 22
+ ilpStreamConnection:
+ id: 'https://openpayments.guide/connections/032da9d5-c9a4-4c80-a354-86b915a04ff8'
+ ilpApddress: g.ilp.iwuyge987y.98y08y
+ sharedSecret: 1c7eaXa4rd2fFOBl1iydvCT1tV5TbM3RW1WLCafu_JA
+ allOf:
+ - $ref: '#/components/schemas/incoming-payment'
+ - type: object
+ properties:
+ ilpStreamConnection:
+ $ref: '#/components/schemas/ilp-stream-connection'
+ unevaluatedProperties: false
+ incoming-payment-with-connection-url:
+ title: Incoming Payment with Connection
+ description: An **incoming payment** resource with the url for the Interledger STREAM Connection resource to use to pay into the payment pointer under this incoming payment.
+ type: object
+ examples:
+ - id: 'https://openpayments.guide/alice/incoming-payments/456da9d5-c9a4-4c80-a354-86b915a04ff8'
+ paymentPointer: 'https://openpayments.guide/alice/'
+ incomingAmount:
+ value: '2500'
+ assetCode: USD
+ assetScale: 2
+ receivedAmount:
+ value: '0'
+ assetCode: USD
+ assetScale: 2
+ expiresAt: '2022-04-12T23:20:50.52Z'
+ createdAt: '2022-03-12T23:20:50.52Z'
+ updatedAt: '2022-03-12T23:20:50.52Z'
+ ilpStreamConnection: 'https://openpayments.guide/connections/782da9d5-c9a4-4c80-a354-86b915a04ff8'
+ allOf:
+ - $ref: '#/components/schemas/incoming-payment'
+ - type: object
+ properties:
+ ilpStreamConnection:
+ type: string
+ format: uri
+ description: Endpoint that returns unique STREAM connection credentials to establish a STREAM connection to the underlying account.
+ readOnly: true
+ unevaluatedProperties: false
+ outgoing-payment:
+ title: Outgoing Payment
+ description: 'An **outgoing payment** resource represents a payment that will be, is currently being, or has previously been, sent from the payment pointer.'
+ type: object
+ examples:
+ - id: 'https://openpayments.guide/alice/outgoing-payments/8c68d3cc-0a0f-4216-98b4-4fa44a6c88cf'
+ paymentPointer: 'https://openpayments.guide/alice/'
+ failed: false
+ receiver: 'https://openpayments.guide/aplusvideo/incoming-payments/45d495ad-b763-4882-88d7-aa14d261686e'
+ receiveAmount:
+ value: '2500'
+ assetCode: USD
+ assetScale: 2
+ debitAmount:
+ value: '2600'
+ assetCode: USD
+ assetScale: 2
+ sentAmount:
+ value: '2500'
+ assetCode: USD
+ assetScale: 2
+ createdAt: '2022-03-12T23:20:50.52Z'
+ updatedAt: '2022-04-01T10:24:36.11Z'
+ metadata:
+ description: APlusVideo subscription
+ externalRef: 'customer: 847458475'
+ - id: 'https://openpayments.guide/alice/outgoing-payments/0cffa5a4-58fd-4cc8-8e01-7145c72bf07c'
+ paymentPointer: 'https://openpayments.guide/alice/'
+ failed: false
+ receiver: 'https://openpayments.guide/shoeshop/2fe92c6f-ef0d-487c-8759-3784eae6bce9'
+ debitAmount:
+ value: '7126'
+ assetCode: USD
+ assetScale: 2
+ sentAmount:
+ value: '7026'
+ assetCode: USD
+ assetScale: 2
+ createdAt: '2022-03-12T23:20:50.52Z'
+ updatedAt: '2022-04-01T10:24:36.11Z'
+ metadata:
+ description: Thank you for your purchase at ShoeShop!
+ externalRef: INV2022-8943756
+ additionalProperties: false
+ properties:
+ id:
+ type: string
+ format: uri
+ description: The URL identifying the outgoing payment.
+ readOnly: true
+ paymentPointer:
+ type: string
+ format: uri
+ description: The URL of the payment pointer from which this payment is sent.
+ readOnly: true
+ quoteId:
+ type: string
+ format: uri
+ description: The URL of the quote defining this payment's amounts.
+ readOnly: true
+ failed:
+ type: boolean
+ description: Describes whether the payment failed to send its full amount.
+ default: false
+ receiver:
+ $ref: ./schemas.yaml#/components/schemas/receiver
+ description: The URL of the incoming payment or ILP STREAM Connection 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.
+ debitAmount:
+ $ref: ./schemas.yaml#/components/schemas/amount
+ description: The total amount that should be deducted from the sender's account when this outgoing payment has been paid.
+ sentAmount:
+ $ref: ./schemas.yaml#/components/schemas/amount
+ description: The total amount that has been sent under this outgoing payment.
+ metadata:
+ type: object
+ description: Additional metadata associated with the outgoing payment. (Optional)
+ createdAt:
+ type: string
+ format: date-time
+ description: The date and time when the outgoing payment was created.
+ updatedAt:
+ type: string
+ format: date-time
+ description: The date and time when the outgoing payment was updated.
+ required:
+ - id
+ - paymentPointer
+ - receiver
+ - receiveAmount
+ - debitAmount
+ - sentAmount
+ - createdAt
+ - updatedAt
+ quote:
+ title: Quote
+ description: A **quote** resource represents the quoted amount details with which an Outgoing Payment may be created.
+ type: object
+ examples:
+ - id: 'https://openpayments.guide/alice/quotes/ab03296b-0c8b-4776-b94e-7ee27d868d4d'
+ paymentPointer: 'https://openpayments.guide/alice/'
+ receiver: 'https://openpayments.guide/shoeshop/incoming-payments/2fe92c6f-ef0d-487c-8759-3784eae6bce9'
+ receiveAmount:
+ value: '2500'
+ assetCode: USD
+ assetScale: 2
+ debitAmount:
+ value: '2600'
+ assetCode: USD
+ assetScale: 2
+ sentAmount:
+ value: '2500'
+ assetCode: USD
+ assetScale: 2
+ createdAt: '2022-03-12T23:20:50.52Z'
+ expiresAt: '2022-04-12T23:20:50.52Z'
+ - id: 'https://openpayments.guide/alice/quotes/8c68d3cc-0a0f-4216-98b4-4fa44a6c88cf'
+ paymentPointer: 'https://openpayments.guide/alice/'
+ receiver: 'https://openpayments.guide/aplusvideo/incoming-payments/45d495ad-b763-4882-88d7-aa14d261686e'
+ debitAmount:
+ value: '7126'
+ assetCode: USD
+ assetScale: 2
+ sentAmount:
+ value: '7026'
+ assetCode: USD
+ assetScale: 2
+ createdAt: '2022-03-12T23:20:50.52Z'
+ expiresAt: '2022-04-12T23:20:50.52Z'
+ additionalProperties: false
+ properties:
+ id:
+ type: string
+ format: uri
+ description: The URL identifying the quote.
+ readOnly: true
+ paymentPointer:
+ type: string
+ format: uri
+ description: The URL of the payment pointer from which this quote's payment would be sent.
+ 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.
+ 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. "
+ expiresAt:
+ type: string
+ description: The date and time when the calculated `debitAmount` is no longer valid.
+ readOnly: true
+ createdAt:
+ type: string
+ format: date-time
+ description: The date and time when the quote was created.
+ required:
+ - id
+ - paymentPointer
+ - receiver
+ - receiveAmount
+ - debitAmount
+ - createdAt
+ page-info:
+ description: ''
+ type: object
+ examples:
+ - startCursor: 241de237-f989-42be-926d-c0c1fca57708
+ endCursor: 315581f8-9967-45a0-9cd3-87b60b6d6414
+ hasNextPage: true
+ hasPreviousPage: true
+ properties:
+ startCursor:
+ type: string
+ minLength: 1
+ description: Cursor corresponding to the first element in the result array.
+ endCursor:
+ type: string
+ minLength: 1
+ description: Cursor corresponding to the last element in the result array.
+ hasNextPage:
+ type: boolean
+ description: Describes whether the data set has further entries.
+ hasPreviousPage:
+ type: boolean
+ description: Describes whether the data set has previous entries.
+ required:
+ - hasNextPage
+ - hasPreviousPage
+ additionalProperties: false
+ json-web-key:
+ type: object
+ properties:
+ kid:
+ type: string
+ alg:
+ type: string
+ description: 'The cryptographic algorithm family used with the key. The only allowed value is `EdDSA`. '
+ enum:
+ - EdDSA
+ use:
+ type: string
+ enum:
+ - sig
+ kty:
+ type: string
+ enum:
+ - OKP
+ crv:
+ type: string
+ enum:
+ - Ed25519
+ x:
+ type: string
+ pattern: '^[a-zA-Z0-9-_]+$'
+ description: The base64 url-encoded public key.
+ required:
+ - kid
+ - alg
+ - kty
+ - crv
+ - x
+ title: Ed25519 Public Key
+ description: A JWK representation of an Ed25519 Public Key
+ examples:
+ - kid: key-1
+ use: sig
+ kty: OKP
+ crv: Ed25519
+ x: 11qYAYKxCrfVS_7TyWQHOg7hcvPapiMlrwIaaPcHURo
+ - kid: '2022-09-02'
+ use: sig
+ kty: OKP
+ crv: Ed25519
+ x: oy0L_vTygNE4IogRyn_F5GmHXdqYVjIXkWs2jky7zsI
+ securitySchemes:
+ GNAP:
+ name: Authorization
+ type: apiKey
+ in: header
+ description: |-
+ The API uses the Grant Negotiation and Authorization Protocol for authorization. An access token must be acquired from an authorization server before accessing the API and then provided in the request headers using the prefix `GNAP`.
+
+ All requests must also be signed using a client key over some select headers and a digest of the request body.
+ responses:
+ '401':
+ description: Authorization required
+ headers:
+ WWW-Authenticate:
+ schema:
+ type: string
+ description: The address of the authorization server for grant requests in the format `GNAP as_uri=`
+ '403':
+ description: Forbidden
+ parameters:
+ cursor:
+ schema:
+ type: string
+ minLength: 1
+ name: cursor
+ in: query
+ description: The cursor key to list from.
+ first:
+ schema:
+ type: integer
+ minimum: 1
+ name: first
+ in: query
+ description: The number of items to return after the cursor.
+ last:
+ schema:
+ type: integer
+ minimum: 1
+ name: last
+ in: query
+ description: The number of items to return before the cursor.
+ id:
+ name: id
+ in: path
+ schema:
+ type: string
+ description: Sub-resource identifier
+ required: true
+ signature:
+ name: Signature
+ in: header
+ schema:
+ type: string
+ example: 'Signature: sig1=:EWJgAONk3D6542Scj8g51rYeMHw96cH2XiCMxcyL511wyemGcw==:'
+ description: 'The signature generated based on the Signature-Input, using the signing algorithm specified in the "alg" field of the JWK.'
+ required: true
+ signature-input:
+ name: Signature-Input
+ in: header
+ schema:
+ type: string
+ example: 'Signature-Input: sig1=("@method" "@target-uri" "content-digest" "content-length" "content-type");created=1618884473;keyid="gnap-rsa"'
+ description: 'The Signature-Input field is a Dictionary structured field containing the metadata for one or more message signatures generated from components within the HTTP message. Each member describes a single message signature. The member''s key is the label that uniquely identifies the message signature within the context of the HTTP message. The member''s value is the serialization of the covered components Inner List plus all signature metadata parameters identified by the label. The following components MUST be included: - "@method" - "@target-uri" - "authorization". When the message contains a request body, the covered components MUST also include the following: - "content-digest" The keyid parameter of the signature MUST be set to the kid value of the JWK. See [ietf-httpbis-message-signatures](https://datatracker.ietf.org/doc/html/draft-ietf-httpbis-message-signatures#section-4.1) for more details.'
+ required: true
+security:
+ - GNAP: []
diff --git a/docs/src/api/schemas.yaml b/docs/src/api/schemas.yaml
new file mode 100644
index 00000000..8a14d434
--- /dev/null
+++ b/docs/src/api/schemas.yaml
@@ -0,0 +1,48 @@
+openapi: 3.1.0
+info:
+ title: Open Payments - Shared schemas
+ version: '1.0'
+ license:
+ name: Apache 2.0
+ identifier: Apache-2.0
+ summary: Open Payments - Shared schemas
+ description: 'Shared schemas used across Open Payments APIs'
+ contact:
+ email: tech@interledger.org
+components:
+ schemas:
+ amount:
+ title: amount
+ type: object
+ properties:
+ value:
+ type: string
+ format: uint64
+ description: 'The value is an unsigned 64-bit integer amount, represented as a string.'
+ assetCode:
+ $ref: '#/components/schemas/assetCode'
+ assetScale:
+ $ref: '#/components/schemas/assetScale'
+ required:
+ - value
+ - assetCode
+ - assetScale
+ assetCode:
+ title: Asset code
+ type: string
+ description: The assetCode is a code that indicates the underlying asset. This SHOULD be an ISO4217 currency code.
+ assetScale:
+ title: Asset scale
+ type: integer
+ minimum: 0
+ maximum: 255
+ description: The scale of amounts denoted in the corresponding asset code.
+ receiver:
+ title: Receiver
+ type: string
+ description: The URL of the incoming payment or ILP STREAM connection that is being paid.
+ format: uri
+ pattern: '^https://(.+)/(incoming-payments|connections)/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$'
+ examples:
+ - 'https://openpayments.guide/alice/incoming-payments/08394f02-7b7b-45e2-b645-51d04e7c330c'
+ - 'https://openpayments.guide/connections/016da9d5-c9a4-4c80-a354-86b915a04ff8'
diff --git a/docs/src/assets/houston.webp b/docs/src/assets/houston.webp
new file mode 100644
index 0000000000000000000000000000000000000000..930c164974ad8eb528878f15a98016249b8cf546
GIT binary patch
literal 98506
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