Title: Open Assets Payment Method Protocol Authors: Oleg Andreev <[email protected]>, Devon Gundry <[email protected]> Status: Draft Created: 2015-05-06
This document defines a protocol for negotiating the assets to be included in an Open Assets Payment Request.
Payment requests help communicate exact transaction requirements to the client. The payment response is either a failure to pay, or a complete transaction exactly satisfying the Payment Request.
This specification solves a problem preceding the actual payment: how do a payer and a payee negotiate which kinds of assets are acceptable for an upcoming transaction? BIP70 does not address this problem because it deals with only one kind of asset, Bitcoin.
We introduce three new types of messages (using the same Protocol Buffers encoding as BIP70):
- A Payment Method Request contains information about the acceptable payment options. The merchant sends this message to the customer.
- A Payment Method contains the exact payment method (types and amounts of assets) that will be used for payment. The customer sends this message to the merchant in reply to a Payment Method Request. The merchant then either replies with a finalized Payment Request or a Payment Method Rejection message.
- A Payment Method Rejection contains information about why the supplied Payment Method is not acceptable.
During the checkout process, a merchant terminal presents a QR code to a customer. The customer scans the QR code with a client wallet to retrieve a Payment Method Request message, which conveys that the merchant accepts both merchant gift card dollars and merchant loyalty points for payment. The message also conveys that the merchant accepts tips (gratuity).
The client wallet recognizes that the customer has both merchant gift card dollars and merchant loyalty points available and prompts the customer to select one or both for payment. The customer selects gift card dollars. The client wallet then prompts the customer to enter a tip. The customer enters a tip and confirms payment. The client wallet then composes a Payment Method message and returns it to the merchant terminal.
The merchant terminal uses the Payment Method message to compose a Payment Request message and returns it to the client wallet. The client wallet then composes the transaction and sends it to the merchant terminal in a Payment message. The merchant terminal displays a payment confirmation to the customer.
Like a Payment Request, a Payment Method Request is optionally tied to a merchant's identity and signed with an x.509 certificate.
message PaymentMethodRequest { optional uint32 payment_details_version = 1 [default = 1]; optional string pki_type = 2 [default = "none"]; optional bytes pki_data = 3; required bytes serialized_payment_method_details = 4; optional bytes signature = 5; }
The meaning and signature validation logic for PaymentMethodRequest is the same as in BIP70.
payment_method_details | See below for a discussion of versioning/upgrading. |
pki_type | Public-key infrastructure (PKI) system being used to identify the merchant. All implementation should support "none", "x509+sha256" and "x509+sha1". |
pki_data | PKI-system data that identifies the merchant and can be used to create a digital signature. In the case of X.509 certificates, pki_data contains one or more X.509 certificates (see Certificates section below). |
serialized_payment_method_details | A protocol-buffer serialized PaymentMethodDetails message. |
signature | digital signature over a hash of the protocol buffer serialized variation of the PaymentMethodRequest message, with all serialized fields serialized in numerical order (all current protocol buffer implementations serialize fields in numerical order) and signed using the private key that corresponds to the public key in pki_data. Optional fields that are not set are not serialized (however, setting a field to its default value will cause it to be serialized and will affect the signature). Before serialization, the signature field must be set to an empty value so that the field is included in the signed PaymentMethodRequest hash but contains no data. |
message PaymentMethodDetails { optional string network = 1 [default = "main"]; required string payment_method_url = 2; repeated PaymentItem items = 3; required uint64 time = 4; optional uint64 expires = 5; optional string memo = 6; optional bytes merchant_data = 7; }
network | Either "main" for payments on the production Bitcoin network, or "test" for payments on test network. If a client receives a PaymentRequest for a network it does not support it must reject the request. |
payment_method_url | Secure (usually https) location where a PaymentMethod message (see below) may be sent to obtain a PaymentRequest. |
items | A list of PaymentItem objects describing different parts of payment (e.g. invoice, tips, donations etc). |
time | Unix timestamp (seconds since 1-Jan-1970 UTC) when the PaymentRequest was created. |
expires | Unix timestamp (UTC) after which the PaymentRequest should be considered invalid. |
memo | UTF-8 encoded, plain-text (no formatting) note that should be displayed to the customer, explaining what this PaymentMethodRequest is for. |
merchant_data | Arbitrary data that may be used by the merchant to identify the PaymentRequest. May be omitted if the merchant does not need to associate Payments with PaymentRequest or if they associate each PaymentRequest with a separate payment address. |
Each item has a type. The default type is "default". Different types could be used in various applications. For example, "tip" type could be used to prompt a customer to add gratuity. Another type "donation" could be used to prompt a customer to donate to a charity. However, types other than "default" are beyond the explicit scope of this specification.
message PaymentItem { optional string type = 1 [default = "default"]; optional bool optional = 2 [default = false]; optional bytes item_identifier = 3; optional uint64 amount = 4 [default = 0]; repeated AcceptedAsset accepted_assets = 5; optional string memo = 6; }
type | Standard identifier of a type of the item. Clients that do not know how to react to a certain type should ignore the PaymentItem if it is optional (see below) or consider request invalid if PaymentItem is not optional. |
optional | Flag indicating whether this payment item is optional or not. If omitted, item is considered required. |
item_identifier | Arbitrary data that may be used by the merchant to identify this item in the PaymentMethod response. |
amount | Number of units to be paid. Possible assets and conversion ratios are covered in AcceptedAsset message. If amount is zero or missing, client may put arbitrary amount. |
accepted_assets | One or more assets acceptable for this item. See below for AcceptedAsset description. |
memo | A human-readable description of the item (summary of the invoice, or name of a charity). |
message AcceptedAsset { optional string asset_id = 1 [default = "default"]; optional string asset_group = 2; optional double multiplier = 3 [default = 1.0]; optional uint64 min_amount = 4 [default = 0]; optional uint64 max_amount = 5; }
asset_id | Open Assets identifier of the asset. Special value "default" (the default value) designates native currency for the current network (e.g. BTC for Bitcoin mainnet). |
asset_group | Arbitrary string describing a group of assets. Client may choose any assets matching the group (e.g. based on Asset Definition file, or defined via other means). If both asset_id and asset_group are missing, raw bitcoins are assumed. |
multiplier | Conversion ratio to estimate how many units of a certain asset are required to satisfy the amount in the payment item (number of asset units must be multiplied by this value to be compared with amount field in the PaymentItem). It does not need to be precise because precise amounts will be computed by the merchant in PaymentRequest. This value is used for UI purposes mostly. |
min_amount | Minimum amount of units of this asset accepted by the merchant. Multiplier is not used to compare units with this value. |
max_amount | Maximum amount of units of this asset accepted by the merchant. Multiplier is not used to compare units with this value. |
When a client chooses a payment method, it replies to the payment_method_url with a PaymentMethod message.
The merchant may match a PaymentMethodItem with PaymentItem objects using either type or item_identifier fields. For type "default", there is usually one field, and therefore, there is no need to specify item_identifier. The client must copy both type and item_identifier to corresponding PaymentMethodItem objects (if they are present).
message PaymentMethod { optional bytes merchant_data = 1; repeated PaymentMethodItem items = 2; } message PaymentMethodItem { optional string type = 1 [default = "default"]; optional bytes item_identifier = 2; repeated PaymentMethodAsset payment_item_assets = 3; } message PaymentMethodAsset { optional string asset_id = 1 [default = "default"]; optional uint64 amount = 2; }
merchant_data | Copied from PaymentMethodDetails.merchant_data. Merchants may use invoice numbers or any other data they require to match Payments to PaymentRequests. Note that malicious clients may modify the merchant_data, so it should be authenticated in some way (for example, signed with a merchant-only key). |
items | List of PaymentMethodItem objects describing assets and amounts used to pay for the corresponding PaymentItem. |
item_identifier | Copied from PaymentItem.item_identifier. Used to match PaymentItemMethod with a corresponding PaymentItem. |
payment_item_assets | One or more payment descriptions of assets for each payment item. |
payment_item_type | Type of payment item as specified in PaymentItem message. |
asset_id | Open Assets identifier of the asset. Special value "default" (also a default) designates native currency on the current network. |
amount | Optional amount to be paid. If specified, Payment Request must contain that amount. If not specified, Payment Request may contain arbitrary amount to ensure the payment item is fully paid. |
If the client specifies unsupported assets or invalid amounts, the merchant may reply with a detailed description of why the payment method negotiation failed.
The rejection message may contain zero or more reasons for rejecting specific assets.
message PaymentMethodRejection { optional string memo = 1; optional uint64 code = 2; repeated PaymentMethodRejectedAsset rejected_assets = 3; } message PaymentMethodRejectedAsset { required string asset_id = 1; optional uint64 code = 2; optional string reason = 3; }
memo | Human-readable reason for rejection, not specific to any asset. |
rejected_assets | Optional list of per-asset rejection reasons. |
code | Optional merchant-defined numeric code of the error. Clients may use this for debugging purposes or to display appropriate UI. |
asset_id | Identifier of the asset that caused rejection. |
reason | Human-readable reason for rejecting the asset. |
Negotiation of payment methods begins with the same URL used by Payment Requests.
To adopt payment methods, clients should add application/oa-paymentmethodrequest
to the Accept:
header when accessing a Payment Request URI. Compatible merchants should reply with a Payment Method Request message and Content-type: application/oa-paymentmethodrequest
. If the client also supports Open Assets or pure Bitcoin payment requests, appropriate MIME types should be added to the Accept:
list and corresponding messages should be expected.
Clients should reply with Payment Method message to payment_method_url
URI with application/oa-paymentrequest
among accepted types. Client SHOULD NOT reply with accepted type application/oa-paymentmethodrequest
to avoid receiving Payment Method Request once again instead of a Payment Request. Content type for Payment Method message (both for request and response) is application/oa-paymentmethod
.
Payment Method Rejection message uses content type application/oa-paymentmethodrejection
.