SPSP Invoices

Preface

This document describes how conduct an Invoice Payment via STREAM once the payment details have been exchanged via the Simple Payment Setup Protocol (SPSP).

Introduction

Invoice Payments

An Invoice Payment is a push payment to an Invoice SPSP Endpoint that allows the Payer (sender) to settle outstanding balances with the Payee (receiver). The Invoice SPSP Endpoint MAY expose the details about the Invoice and, when receiving value, updates its outstanding balance accordingly.

Motivation

The Simple Payment Setup Protocol (SPSP) only describes how the details required for a STREAM connection are exchanged and how simple push payments are made. Invoices require the SPSP server to keep track of incoming payments, i.e. act as an accounting server.

Scope

This document specifies Invoice specific endpoints on SPSP and payments to these. They are intended for wallet providers and merchants.

Definitions

  • Invoice - A set of parameters describing the nature of the value transfer as well as its terms and status.
  • Invoice Payment - The process of completing an Invoice by transferring value to its corresponding Invoice SPSP Endpoint.
  • Payer - The entity that is sending units of value to an Invoice SPSP Endpoint on the Payee's SPSP Server. It is running the SPSP Client.
  • Payee - The entity that is creating an Invoice SPSP Endpoint and receives units of value from the Payer using this Invoice SPSP Endpoint. It is running the SPSP Server.
  • Invoice Payment Pointer - A Payment Pointer that includes a unique and opaque string and represents an Invoice. The SPSP Client uses it to query the SPSP Endpoint on the SPSP Server, which MAY expose the details of the Invoice. It is the means by which the Payee keeps track of incoming payments.

Operation Overview

The Payer's SPSP Client will set up a STREAM connection to the Payee's SPSP Server using the Invoice Payment Pointer, as described by the Simple Payment Setup Protocol. On connection, the SPSP Client pushes as much value to the SPSP Server as necessary to complete the Invoice.

Model of Operation

Creating an Invoice Payment Pointer

Prior to the Invoice Payment, the Payee has to create the Invoice Payment Pointer representing the Invoice. This Invoice Payment Pointer MUST be unique to the Invoice. The Payee's SPSP Server SHOULD store the Invoice details associated to the Invoice Payment Pointer, which are defined in the invoice-object within the Response Body, in order to account for balance changes.

Conducting an Invoice Payment

The Payer's SPSP Client opens a STREAM connection to the Payee's SPSP Server as described in the Simple Payment Setup Protocol. Once this connection is established, the process continues as follows:

The SPSP Client begins sending ILP packets using the STREAM protocol to complete the Invoice.

  1. The SPSP Client will adjust their sendMax to reflect the amount they're willing to send.
    • sendMax SHOULD be derived from the Invoice, i.e., sendMax SHOULD be equal to push.invoice.amount - push.balance, converted to the SPSP Client's operating asset, plus a buffer to take exchange rate fluctuations and connector fees into account.
  2. The SPSP Server will adjust their receiveMax to reflect the amount they're willing to receive.
    • receiveMax SHOULD be derived from the Invoice, i.e., sendMax SHOULD be equal to push.invoice.amount - push.balance, converted to the SPSP Server's operating asset, plus a buffer to take exchange rate fluctuations into account.
  3. The SPSP Client's and Server's STREAM Modules will move as much value as possible while staying inside these bounds.
  4. If the SPSP Client reaches their sendMax, they end the stream and the connection. If the SPSP Server reaches their receiveMax, they will end the stream and the connection. Furthermore, when the SPSP Server has received enough value to fully pay the invoice, it ends the stream and the connection. In both cases, the connection is closed with a NoError code in the ConnectionClose frame.

The STREAM parameters--sendMax and receiveMax--as well as the ConnectionClose frame are defined in STREAM's frame encoding.

Specification

Query (GET <SPSP Endpoint>)

The SPSP Client queries the Invoice Payment Pointer to get information about the SPSP Server as well as Invoice specific details:

Request

GET /invoice123 HTTP/1.1
Host: example.com
Accept: application/spsp4+json

Response

HTTP/1.1 200 OK
Content-Type: application/spsp4+json

{
  "destination_account": "example.ilpdemo.red.invoice123",
  "shared_secret": "6jR5iNIVRvqeasJeCty6C+YB5X9FhSOUPCL/5nha5Vs=",
  "push": {
    "balance": "5360",
    "invoice": {
      "amount": "19999",
      "asset": {
        "code": "USD",
        "scale": 2
      },
      "additional_fields": {
        "description": "Chair model 'Rustic'",
        "receiver": "The Red Furniture Store"
      }
    }
  }
}
Response Body

The response body is a JSON object that includes basic account details necessary for setting up a STREAM connection as well as optional parameters for displaying purposes. The fields are defined in the following:

Field Type Description
destination_account ILP Address (see Simple Payment Setup Protocol)
shared_secret 32 bytes, base64 encoded (including padding) (see Simple Payment Setup Protocol)
push Object Details of this specific push payment pointer.
push.balance String Integer Amount, denoted in push.invoice.asset.code, which completes the invoice payment.
push.invoice Object Invoice details.
push.invoice.amount String Integer Amount, denoted in push.invoice.asset.code, which needs to be received in order for the invoice to be considered as paid.
push.invoice.asset Object Details about the Invoice's asset.
push.invoice.asset.code String Asset code to identify the Invoice's currency. Currencies that have ISO 4217 codes should use those.
push.invoice.asset.scale Integer The scale of the amounts denoted in push.invoice.asset.code (e.g. an amount of "1000" with a scale of 2 translates to 10.00 units of the SPSP server's asset/currency).
push.invoice.additional_fields Object (OPTIONAL) Any additional information the Payee wants to include.

Note: Currency amounts are denominated as integer strings instead of native JSON numbers to avoid losing precision during JSON parsing. Applications MUST represent these numbers in a data type that has precision equal or greater than an unsigned 64-bit integer.

Errors
pointer Does Not Exist
HTTP/1.1 404 Not Found
Content-Type: application/spsp4+json

{
  "id": "InvalidPointerError",
  "message": "Pointer does not exist."
}