Direct Payment Protocol
by Bernhard Müller, Krzysztof Fonał on 24 October 2022
Expiry date
Licence
Open BSV License
Applies to
Wallets
Standard Stage
In Consideration Draft Internal Review Public Review Published Recommended
Thanks for submiting your comments!

TS 2021.014

Direct Payment Protocol

Attribute Description
Version1.0
AuthorsBernhard Müller, Krzysztof Fonał
ReviewersAleksandar Dinkov, Darren Kellenschwiler, Jad Wahab, Janez Urevc, Jonathan Vaage, Kapil Jain, Rafa Jimenez, Roger Taylor
Tags and CategoriesInvoices, Payments, BIP270, BIP271, BIP272, BIP273, BIP274, BIP275, BIP282 P2P, Requests, Meta-Assets
Publication Date24/10/2022
Valid Untiln/a
Copyright2022 Bitcoin Association for BSV
IP GenerationGB2118959.2 – Direct Payment Protocol (DPP)
Known Implementationsn/a
Applies ToPayments, Micropayments, Merchants, Consumers, Payees, Collection, Cash Handling
BRFC IDn/a
AcknowledgementsThe Authors would particularly like to thank the following people for their significant contributions to standard document: Aleksandar Dinkov and Jad Wahab
StatusPublished
VisibilityPublic

Background

This standard serves two purposes:

  1. Ensure a well maintained source of information for all invoice based payment standards (currently BIP270, BIP271, BIP272, BIP273, BIP274, BIP275, BIP282) and related invoicing standards such that new industry players and developers find up to date and accurate information.
  2. Harmonize extensions to BIP270, BIP271, BIP272, BIP273, BIP274, BIP275, BIP282 to allow invoicing for different payment options as well as combinations of payment options either in a single transaction or in multiple transactions.

Problem Statement

Currently BIP270, BIP271, BIP272, BIP273, BIP274, BIP275, BIP282 are not owned by a standards committee. Several versions exist on GitHub and they all share one thing in common: They don’t represent the current implementations in the field. This makes it very hard for new players to come in and get invoice based payments right the first time.

Further, many industry representatives have voiced the need for an extension to the current standard which, for example, could allow for payments in meta-assets or the accepting of discount coupons which lower the amount of BSV required to successfully satisfy the invoiced amount.

Objectives

  1. Re-evaluate the current BIP270, BIP271, BIP272, BIP273, BIP274, BIP275, BIP282 standard and baseline it to the common field implementation.
  2. Maintain backwards compatibility.
  3. Collect extension wishes and needs from industry players.
  4. Find the smallest denominator for such extension needs.
  5. Allow for future custom extensions without jeopardizing backwards compatibility (e.g. Travel Rule information, SPV information, etc.).
  6. Publish the standard/BIPs publicly (e.g. GitHub) and advertise it through the appropriate channels to spur adoption.
  7. Maintain the standard/BIPs.

Scope

Invoice Based Payments, BIP270, BIP271, BIP272, BIP273, BIP274, BIP275, BIP282

Out of Scope: Topics covered by other working groups such as merchant-payee address resolution, and Simplified Payment Verification (SPV) transaction validation.

Methods and Concepts

  1. Intro session with all interested participants. Understanding of interests and needs. Introduction to the existing draft proposal. Potential break out sessions for particular needs after. Collection of Requirements.
  2. Formation of core group which writes the actual standard and makes sure requirements collected in phase 1 are covered as well as possible.
  3. Preliminary rollout and implementation phase. Collection of Feedback from these implementations.
  4. Amendments based on Feedback.
  5. Publication and Rollout.
  6. Maintain standard.

Specification

Abstract

This RFC describes a protocol for communication between a payment host (usually either a merchant, a payment processor, or simply the recipient’s wallet) and sender (a customer, acquaintance, or device like an IoT device – an entity known to the receiver). It aims to improve customer experience, simplifying wallet infrastructure to make more advanced wallet features such as multiple outputs easier to implement, and to improve wallet security against payment process attacks such as man-in-the-middle.

Please note that the “payment host” in this document may not actually be the recipient of the funds. Like BitPay, the payment host may actually be a host or payment processor who is providing this protocol as a service for another party who is the actual recipient of the funds. We have chosen the name “payment” host to be an abstraction over either a merchant, a payment processor, a wallet, or any other agent that receives funds or acts as a proxy to whoever is the true recipient of the funds.

Motivation

The naive Bitcoin payment protocol operates as follows:

  1. Customer decides to checkout while online shopping, and chooses to pay using Bitcoin.
  2. Payment host generates a unique payment address, generates an invoice for the customer, updates the invoice with the payment address, and displays the invoice on an order completion web page.
  3. Customer copies the Bitcoin address from the payment host’s web page and pastes it into whatever wallet they are using, or follows a bitcoin: link (e.g., scans a QR code from a wallet on their smart phone) and their wallet is launched with the amount to be paid.
  4. Customer authorizes payment to the merchant and their wallet posts the transaction to a wallet server which posts the transaction to a Bitcoin node.
  5. Payment host’s server continuously scans the Bitcoin blockchain until the payment is detected, and after the transaction reached a certain threshold of transaction confirmations set by the merchant, it is considered settled.

There are several major problems with the naive approach. First, it requires the customer broadcast the transaction; meaning the customer’s wallet must connect to the Bitcoin network, and the payment host must wait for the transaction to be validated and propagate before accepting the payment. Second, it has no ability to allow for multiple outputs, which is necessary for many interesting use-cases of Bitcoin such as OP_RETURN data. Third, there is no reliable way for a payment host to refund a payment in case of an issue.

This RFC extends the naive protocol to simplify wallet construction, add new wallet features, and help make exponential ‘on-chain’ scaling possible; to the effect of enabling Bitcoin nodes to accommodate all future global network communications:

  1. Flexible payment destinations: can be human-readable (customers will be asked to authorize payment to “http://example.com ” instead of an inscrutable 34-character bitcoin address), support for various tokens protocols, support for native approach (from BIP270).
  2. Secure proof of payment, which customers can use in the event of a dispute with the merchant.
  3. Protection from man-in-the-middle attacks that replace a payment host’s receiving Bitcoin address with an attacker’s address before a transaction is authorized with a hardware wallet.
  4. Payment is sent directly to the payment host, removing the necessity of the customer engaging with the Bitcoin p2p network, and enabling quicker confirmation.
  5. Payment received messages, so the customer knows immediately that the payment host has received, and has processed (or is processing) their payment.
  6. Originator data automatically given to the payment host by the customer’s wallet software, so payment hosts e.g. do not have to contact customers before refunding overpayments or orders that cannot be fulfilled for some reason. Originator data can be used also for various other cases e.g. promotions (like every 10th payment from the same customer will trigger send voucher back).
  7. Payment can contain multiple outputs which can be arbitrary scripts and not just addresses, making new applications possible.
  8. It is no longer necessary for wallets to connect to the Bitcoin p2p network to broadcast transactions.
  9. It is no longer necessary for payment hosts to maintain an address index to monitor for in coming transactions.

Protocol

This specification describes payment protocol messages encoded using JSON, authenticated and communicated using HTTPS or other authentication and communication systems (such as the blockchain itself). Future BIPs might extend this payment protocol to other encodings, PKI systems, or transport protocols.

The payment protocol consists of three messages; PaymentTerms, Payment, and PaymentACK, and begins with the customer somehow indicating that they are ready to pay and the payment host’s server responding with a PaymentTerms message:

Messages

There are several JSON objects used in the protocol. We start with a summary of the JSON objects, and then proceed to the details. Top-level objects are the messages type at the same time.

  • PaymentTerms: A way of specifying the details of a required payment, including a dict of destinations, expiration data, and other meta data. This message/object contains 2 main parts (and a few variables):
    1. Modes: Payment modes where each mode describes detailed instruction about payment requirements, where requirements are embedded in specified format (Payment Mode)
    2. Beneficiary: A way of specifying data about merchant.
    3. Policies: A way of specifying special merchant’s requirements according to Payment object.
  • Payment: Includes a signed Bitcoin transaction. Detailed format of Payment depends on chosen Payment Mode but the below object is common for all modes:
    1. Originator: A way of specifying data about payer.
  • PaymentAck: Acknowledgement of receipt of payment. Detailed format of PaymentACK depends on chosen Payment Mode but the below object is common for all modes
    1. PeerChannel: A way to provide data needed to communicate via created channel in a secure manner.

PaymentTerms

A payment request contains the information the consumer needs to make the payment to the payment host.


PaymentTerms {
    network // string. required.
    version // string. required. 
    outputs // an array of outputs. optional, deprecated - for backward compatibility.
    creationTimestamp // number. required.
    expirationTimestamp // number. optional.
    memo // string. optional.
    paymentUrl // string. required.
    beneficiary // object. optional.
    modes // a key-value map. required.
    policies // object. optional.
}
networkThis field is required and should be ‘bitcoin-sv’ always. You might change it in a development environment for testing purposes (e.g. testnet stn regtest) but in production for direct payment requests on BSV mainnet, it should be ‘bitcoin-sv’ to be backward compatible with most wallets which support current BIP270 implementations.
outputsOne or more outputs where Bitcoins are to be sent. Deprecated (for backward compatibility only).
creationTimestampUnix timestamp (seconds since 1-Jan-1970 UTC) when the PaymentTerms was created.
expirationTimestampUnix timestamp (UTC) after which the PaymentTerms should be considered invalid.
memoNote that should be displayed to the customer, explaining what this PaymentTerms is for. Maximum length is 50 characters.
paymentUrlSecure HTTPS location where a Payment message (see below) will be sent to obtain a PaymentACK.
beneficiaryArbitrary data that may be used by the payment host to identify the PaymentTerms. May be omitted if the payment host does not need to associate Payments with PaymentTerms or if they associate each PaymentTerms with a separate payment address.
modespossible, specified by ID (and well defined) modes customer can choose to pay. More about the modes and first defined mode can be find here.
policiesDescribe extra requirements needed to process the Payment, e.g. requirements of optional originator fields (merchant might require refund_address for instance to process the payment)

The paymentUrl specified in the PaymentTerms should remain valid at least until the PaymentTerms expirationTimestamp (or as long as possible if the PaymentTerms does not expire). Note that this is irrespective of any state change in the underlying payment request; for example cancellation of an order should not invalidate the paymentUrl, as it is important that the payment host’s server can record mis-payments in order to refund the payment.

When a Bitcoin wallet application receives a PaymentTerms, it must authorize payment by doing the following:

  1. Validate the payment host’s identity and signature using the PKI system. The PKI system is assumed to occur in a wrapper layer (such as HTTPS) and if no PKI system is available then the wallet can choose whether or not to display the payment request. The PKI system is usually HTTPS, and as such if the payment request is retrieved over HTTPS then the domain name should be displayed as the payment host.
  2. Validate that customer’s system unix time (UTC) is before PaymentTerms.expirationTimestamp. If it is not, then the payment request must be rejected.
  3. Display the payment host’s identity and ask the customer if they would like to submit payment (e.g. display the “Common Name” in the first X.509 certificate).

PaymentTerms messages larger than 10 MB should be rejected by the wallet application, to mitigate denial-of-service attacks.

Example:

{
  memo: "Payment for purchasing Socks online",
  network: mainnet,
  creationTimestamp: 1648163657,
  expirationTimestamp: 1648164657,
  paymentUrl: https://localhost:3443/api/v1/payment/Order-325214,
  beneficiary: {
    name: "GoldenSocks.com",
    email: "[email protected]
    address: wonderland 25, Nicecountry
    paymentReference: "Order-325214",
  },
  policies: {
    requiredOriginatorFields: [paymail]
  }
  modes: {
  'ef63d9775da5': { // HybridPaymentMode
      choiceID0: {
        transactions: [
          {
            outputs: {
              native: [
                {
                  satoshis: 10000000,
                  script: "76a91493d0d43918a5df78f08cfe22a4e022846b6736c288ac",
                },
              ],
            },
            policies: {
              fees: {
                  standard: {
                    satoshis: 1,
                    bytes: 1
                  },
                  data: {
                    satoshis: 1,
                    bytes: 10
                  }
                },
              SPVRequired: false
            }
          },
        ],
      },
      choiceID1: {
        transactions: [
          {
            outputs: {
              native: [
                {
                  satoshis: 10000,
                  script: "76a91493d0d43918a5df78f08cfe22a4e022846b6736c288ac",
                },
              ],
              brfc1: [ // please note that this is only example, RUN protocol schema might be differ
                {
                  contractName: "MyToken",
                  contractType: "RUN's word for Standard Fungible Token", // this will further devide the sub-protocol into sub-sub-protocols.
                  contractLocation:
                    "bc64f3ab1ffe7b4396097b9611ed4105ac5994901202c84b334708d6cc42067a_o1",
                  tokenAmount: 400,
                  tokenRecepient: "1DjmxqX7AnzQe6rUyG1AibPhUCXLJyoMVU",
                },
              ],
            },
            inputs: {
              native: [
                {
                  // input #1
                },
              ],
              // brfc100: [
              //     {}
              // ]
            },
            policies: {
              ancestry: { format: "binary", minDepth: 2 },
              SPVRequired: false
              // can be extended with "req-" parameter if extensions are Required!
            },
            // can be extended with "req-" parameter if extensions are Required!
          },
          {
            outputs: {
              STAS: [ // please note that this is only example, STAS protocol schema might be differ
                {
                  satoshis: 10000,
                  script: "some really long STAS script",
                  contractTX: "XYZ",
                  contractAddress: "ABC",
                },
              ],
            },
            policies: {
              ancestry: { format: "binary", minDepth: 2 },
              SPVRequired: false
            },
          }
        ],
      },
    }
  }
}

a. Modes

Required outputs packed inside some specified mode. PaymentTerms might provide various modes and the customer or wallet logic has to choose which mode it’s going to use. Chosen mode then dictates how the Payment and PaymentACK objects will look like to fit the chosen mode’s flow and requirements. More information about PaymentModes can be found <here>.

b. Beneficiary

The beneficiary data contains information about the merchant.

Beneficiary {
  name // string. required.
  email // string. required.
  address // string. required.
  paymentReference // string. ID of invoice. required.
  avatar // string. optional.
  extendedData // object. optional, freestyle object.
}
nameName of merchant.
avatarURL to an avatar.
emailOfficial merchant email.
addressMerchant’s address.
paymentReferenceID of the payment/invoice.
extendedDataAdditional optional data.

c. Policies

Policies defines extra merchant’s requirements. At this version of DPP the only one are related to required Originator fields (e.g. if payer doesn’t provide paymail, the payment won’t be processed) but in the future it might be extended (e.g. travel rule might be required by merchant, payers country might be limited etc.)

Policies {
  requiredOriginatorFields // an array. optional.
}
requiredOriginatorFieldsList of the fields which are required by merchant to process the payment (regardless DPP defines them as optional ones).

Payment

Payment messages are sent after the customer has authorized payment. It refers to which payment mode was chosen and provides the specific data required for the particular mode:

Payment {
  modeId // string. The chosen mode
  mode // object. The Payment object for the specific mode used.
  originator // object. payer data needed for identification as well as refund. optional.
  transaction // a hex-formatted (and fully-signed and valid) transaction. optional. deprecated
  memo // string. optional.
}
modeIdMode chosen from possible modes of PaymentTerms.
modeObject with data required by specific mode, e.g. HybridPaymentMode
originatorData about payer. This data might be needed in many cases, e.g. refund, tract data for later loyalty points processing etc.
transactionA single valid, signed Bitcoin transaction that fully pays the PaymentTerms. This field is deprecated.
memoA plain-text note from the customer to the payment host.

When the payment host’s server receives the Payment message, it must determine whether or not the transactions satisfies conditions of payment terms. If and only if they do, it should broadcast the transaction to the the Bitcoin p2p network.

Payment messages larger than 10 MB should be rejected by the payment host’s server, to mitigate denial-of-service attacks.

Example:

{
  modeId: "ef63d9775da5", // This ID is brfcid for HybridPaymentMode"
  mode: {
    ...  //HybridPaymentMode Payment object
  },
  originator: {
    name: "Aleks Dinkov",
    paymail: "[email protected]",
    avatarUrl: "https://iamges.com/vtwe4eerf",
  }
}

a. Originator

A payer data contains info about payer of the TX.

Originator {
  name // string. required.
  paymail // string. optional.
  return_address // string. optional
  return_script // string. optional
  avatar // string. optional.
  extendedData // object. optional, freestyle object.
}
nameName of payer.
avatarURL to an avatar.
paymailPayer’s paymail (where e.g. refunds will be send, identity can be use somehow etc.)
return_addressPayer’s return bitcoin address on which merchant can refund the payment back if there is such case (if paymail cannot be used, other way paymail is better option).
return_scriptSimilar like above but script instead of raw address (it is more flexible, e.g. payer might want to have a refund in stable coin).
extendedDataAdditional optional data.

b. Ancestor

The details about this object are referenced The details about this object are referenced in the Transactions Ancestors Standard

https://tsc.bitcoinassociation.net/standards/transaction-ancestors/


PaymentACK

PaymentACK is the final message in the payment protocol; it is sent from the payment host’s server to the bitcoin wallet in response to a Payment message:

PaymentACK {
  modeId // string. The chosen mode
  mode // object. The Payment object for the specific mode used.
  peerChannel // object. optional
  redirectUrl // string. optional
}
modeIdMode chosen from possible modes of PaymentTerms.
modeObject with data required by specific mode, e.g. HybridPaymentMode.
peerChannelData which specify created channel for secure direct communication. More info can be found here.
redirectUrlOptional URL where merchant wants customer to redirect after payment is done.

Example:

{
  modeId: "ef63d9775da5", // This ID is brfcid for HybridPaymentMode"
  mode: {
    ...  //HybridPaymentMode PaymentACK object
  },
  peerChannel: {
    host: "peerchannels:25009",
    token: "token",
    channel_id: "channelid",
  },
}

PaymentACK messages larger than 11 MB bytes should be rejected by the wallet application, to mitigate denial-of-service attacks. This is larger than the limits on Payment and PaymentTerms messages as PaymentACK contains a full Payment message within it.

Payment Modes

This is the main part of the PaymentTerms object. For now we propose one, flexible payment mode which you can use to pay with BSV, tokens, or a combination of funding sources (called HybridPaymentMode). In the future if HybridPaymentMode cannot fullfil some requirements, other PaymentModes can be specified. Chosen payment mode also has impact on the format of Payment and PaymentACK objects which might differ for different modes.

In the next section, predefined mode – HybridPaymentMode will be described together with related Payment and PaymentACK objects.

HybridPaymentMode (BRFCID: ef63d9775da5)

This is first defined payment which may fullfil a lot of requirements because of its flexible nature. It allows for a payment host to stipulate payment from a set of funding types created with AND and OR connections. With this arrangement a payment host can define a set of various outputs (tokens + BSV + loyalty points + stable coins) or even multiple equivalent alternatives to successfully fund the transaction. The wallet may chose which option depending upon user resources. This is the definition of the mode:

Options {
  "ID": Transactions // required, min one key-value pair.                   
}

So this payment mode just contains a dictionary of various options (options are OR relation, so they are alternative sets of outputs and the customer or their wallet will pick one).

Options (In PaymentTerms)

Every option contains a set of transactions (AND relation, if the customer chooses the option they must provide all the required funds to satisfy the transaction). Below you can find the interface for transaction object and transaction’s internal objects.

Transaction

Transaction object is a set which contains 3 parts:

  1. Outputs: A way of specifying a Bitcoin transaction output, including the value and script for various token standards.
  2. Inputs: A way of declaring which specific inputs should be used (useful for multisig, payment_channels etc).
  3. Policies: A way of requesting specific TX policies like fees, SPV, nLockTime etc.
Transaction {
  outputs // list of output objects. required
  inputs // list of input objects. optional
  policies // additional properties and requirements for transaction. optional
}

Outputs

List of outputs – payment destinations.

Outputs {
  native // list of native output objects. optional.
  brfcXYZ // list of brfc objects of XYZ token. optional.
  tokenABC // list of ABC token objects. optional.
  ...
}
Native output

This is regular native BSV output which specify amount and recipient in bitcoin script form (usually p2pkh).

Native output {
  amount // number. required.
  script // string. required. hexadecimal script.
  description // string. optional. must not have JSON string length of greater than 100.
}
amountNumber of satoshis (0.00000001 BSV) to be paid.
scriptA “TxOut” script where payment should be sent, formatted as a hexadecimal string.
descriptionAn optional description such as “tip” or “sales tax”. Maximum length is 50 characters.
STAS output

This is output used for getting tokens using STAS protocol. It required to define tokenId (with symbol), amount and recipinet.

Native output {
  tokenId // string. required.
  amount // number. required.
  recipient // string. bitcoin address or paymail.
}
tokenIdToken identificator in form issuerAddress-symbol.
amountNumber of token to be sent.
recipientRecipient to who token(s) is/are sending. Format might be regular bitcoin address or paymail.

TokenXYZ

Structure for this object is specific for each particular token standard. This may be based on BRFC reference if said token standard hasn’t published a name yet or otherwise based upon a particular token’s name. Below are two example schemas:

brfc1234 {
  properties_1
  properties_2
  ...
}

unicornToken {
  tokenId // string. required
  script // string. required. hexadecimal script.
  ...
}
Inputs

A list of inputs object contains data needed to specify the required inputs which should be used.

Input {
  scriptSig // string. required.
  txid // string. required.
  vout // integer. required.
  value // integer. required.
  nSequence// number. optional.
}
scriptSigThe hexadecimal unlocking script for the input UTXO (or an empty string)
txidThe transaction index of the transaction containing the input UTXO.
voutThe index of the UTXO in the transaction.
valueThe amount of satoshis locked in the input UTXO.
nSequenceSpecific nSequence value required in transaction which will be created from the PaymentTerms. If set as non-default makes transaction not final (it goes to non-final mempool). More info: https://wiki.bitcoinsv.io/index.php/NLocktime_and_nSequence
Policies

An object containing some policy information like fees or spv envelope.

Policies {
  fees // dictionary. optional. Nested dictionary which include on Fee objects on 3rd level.
  SPVRequired // boolean. optional. default is false.
  lockTime // number. optional.  
}
feesDictionary containing “data” and “standard” keys which points to another dictionary with “mining“ and “relay” keys. “mining” and “relay” points to Fee object. It looks like this:
"fees": {
"data": {
"satoshis": ..,
"bytes": ..,
},
"standard": {
"satoshis": ...,
"bytes": ...,

}
}
SPVRequiredPoints if it is required to provide merkle proof
lockTimeSpecific nLockTime value required in transaction which will be created from the PaymentTerms. If not set, default is 0 what means transaction will be mined by miner as soon as possible. Other value then zero request a delay. More info: https://wiki.bitcoinsv.io/index.php/NLocktime_and_nSequence

Mode (In Payment)

This object defines fields required by HybridPaymentMode. In this mode important data are chosen for payment option (paymentId) and a list of transactions which fulfil this option:

"ef63d9775da5" {
  optionId // string. ID of chosen payment options
  transactions // a list of raw transactions. required
  ancestors // object. optional.
}
transactionsA list of valid, signed Bitcoin transactions that fully pays the PaymentTerms. The transaction is hex-encoded and must NOT be prefixed with “0x”. The order of transactions should match the order from PaymentTerms for this mode and option.
optionIdIdentification of chosen option from PaymentTerms.
ancestorsAncestor TX together with MerkleProof needed when SPV is used. More info about it you can find here.

Example:

{
  optionId: "choiceID1",
  transactions: [
    " RAW_TRANSACTION for 'choiceID1.transactions[0]' ",
    " RAW_TRANSACTION for 'choiceID1.transactions[1]' ",
  ],
  ancestors: {
    " TXID of RAW_TRANSACTION for 'choiceID1.transactions[1]' ": {
      /* This object has the ancestors of 'choiceID1.transactions[1]' */
    },
  }
}


Mode (In PaymentACK)

This object defines fields required by HybridPaymentMode:

{
  transactionIds // a list of transaction ids. required
  peerChannel // object. optional
}
transactionIdsList of transaction IDs from the Payment transactions which were broadcast by merchant.
peerChannelData which specify a created channel for secure direct communication. More info can be found here.

Example:

{
  transactions: [
    " TXID of transaction for 'choiceID1.transactions[0]' ",
    " TXID of transaction for 'choiceID1.transactions[1]' ",
  ],
  // Things like peer_channel should probably still be defined at the paymentAck root level. Different transactions should probably not have different peer_channel-s.
  peerChannel: {
    host: "peerchannels:25009",
    token: "token",
    channel_id: "channelid",
  },
}

API definition

Below is the table with messages requested from client (wallet) to merchant (server).

PaymentID parameter is assumed to be known as a result of request between client-server before DPP protocol operation (the first request/response on the diagram).

Message Endpoints Type/SubtypeResponse codes
PaymentTermsGET
/api/v1/payment/{paymentID}
application/json200 – contains PaymentTerms JSON object with all data used by the payee to construct a transaction
404 – returned if the paymentID has not been found
500 – returned if there is an unexpected internal error
PaymentPOST
/api/v1/payment/{paymentID}
application/json201 – contains PaymentACK JSON object
400 – returned if the user input is invalid, usually an issue with the paymentID
404 – returned if the paymentID has not been found
500 – returned if there is an unexpected internal error

For more info you can refer to: https://jadwahab.github.io/direct-payment-protocol/#/


URI Scheme

URI scheme for 4P protocol represents a scheme for downloading the PaymentTerms object; which is the beginning of the payment process.

The URI is to allow users to click on a link in a web page, email or scan a QR codes to initiate the payment protocol.

The scheme is following:

pay:?r=https://merchant.com/pay.php?h%3D2a8628fc2fbe

Certificates

The original BIP 70 which this spec is based on included signatures from X.509 certificates (the same certificates used for SSL / TLS / HTTPS). We follow BIP270 which assumes the authentication happens at a separate layer and as such for simplicity we have removed authentication. Wallets should use other mechanisms to determine the name and identify of the recipient in a secure manner. Under the usual case on the web, DPP messages will be sent and received over HTTPS, which uses X.509 certificates, and thus the wallet should simply show the domain name under most cases. HTTP (and insecure form of HTTPS) should not be supported. Additional security layer is provided experimentally here https://jadwahab.github.io/direct-payment-protocol/#/ (/sec/ endpoints) and might be included in future DPP protocol versions.

Extensibility

We use JSON as JSON is naturally extensible. Any property of the objects not specified in this spec is a candidate to convey information for extensions.

History

Artefact Description
Erratan/a
Change Logn/a
Decision LogSee Supplementary Material

Relationships

Relationship Description
IP licences and dependenciesnChain Patent Pledge for Merkle Proof Standardized Format Specification
Copyright© 2022 Bitcoin Association. All rights reserved.

Unless otherwise specified, or required in the context of its implementation on BSV Blockchain, no part of this standard may be reproduced or utilised otherwise in any form or by any means, electronic or mechanical, including photocopying, or posting on the internet or an intranet, without prior written permission of Bitcoin Association.
Extendsn/a
Modifies n/a
Deprecates n/a
Depends On n/a
Prior Art Foundation:

BIP70
BIP270
BIP271
BIP272
BIP273: (not addressed → In my opinion it goes beyond BIP270, like it is about requesting invoice from customer to merchant, so before P4 starts. This is implemented by merchant’s individual API to which customer/wallet has to request for purchase order)
BIP274
BIP282
Existing Solution n/a
References n/a

Supplementary Material

Summary of the comments

The comments received were very diverse and lead to a lot of great discussions around a few topics including but not limited to these:

  • Should the protocol be more fundamentally changed than building on BIP270 implementations out there today? Like e.g. but not limited to: Should the originator be able to choose how to fulfill the payments with Bitcoin outputs instead of the requestor? Should it be backward compatible or start on a clean slate?
  • Modularity and rigidity of the standard. The most open standard is no standard, but then what’s the point of a standard? A lot of use cases were considered by many reviewers and the goal of the workgroup was to accommodate as many of them as possible
  • Comments around what information should be requested from the payment originator if any at all.
  • The interfaces of IT networking and use cases the standard may be used for. Is a consumer-to-merchant transaction peer-to-peer? Socially these are not peers at the time. Is there a limitation to the interactions this protocol can be used with? These comments resulted in a lot of discussions around the name of DPP which was at the time proposed as “Invoice Based Payments”.

Summary of the decision log

  • As initially proposed the standard was heavily built on how BIP270 payments which are implemented by major industry players today, especially by mobile wallets and interfaces. The party posing a payment request decides which options for fulfillment exist. The standard also maintains two fields that are depreciated at a point where all industry players had a chance to upgrade to DPP. So by still providing values in these two fields DPP payment requests are compatible with providers which don’t interpret DPP payment modes information yet.
  • Despite extensive review and participation in the workgroup it became clear that not all future use cases can be foreseen today and that the ideas we have today already need a lot of flexibility. Therefore the concept of the payment mode was introduced into the standard. This allows not only for today and future use cases but allows the standard to be used also by various token protocols and for almost any type of bitcoin script.
  • DPP allows for sending some default originator fields and also allows to extend the information that can travel with the transaction, such as information used from other standards such as the Travel Rule Standard or e.g. eligible buyer information. The requester of the payment can signal the policy in the payment request.
  • The name of the standard that found an overwhelming majority was “Direct Payment Protocol (DPP)”.
Record an Implementation

To record an implementation of the standard, please register below.

Already have an account?
Request for a Review or Withdrawal

To request for a review or withdrawal of the standard, please register below.

Already have an account?
Tags
Suggest new tags for this standard
or
Overview
Overview
Become a Contributor
If you wish to join us on this mission to make BSV the public blockchain of choice please fill in our preliminary registration form below. We look forward to having you on board.