PaymentProtocol

Protocol.PaymentProtocol History

Hide minor edits - Show changes to output

Changed lines 53-55 from:
Protocol extensions may add custom fields to Ripple messages, as well as defining their own host and/or node messages.  Nonstandard extensions should take care not to duplicate field names of other extensions, by, for example, giving their field names a short common prefix that identifies the protocol extension to which they belong.

to:
Protocol extensions may add custom fields to Ripple messages, as well as defining their own host and/or node messages.  Nonstandard extensions should take care not to duplicate field names of other extensions, by, for example, giving their field names a short common prefix that identifies the protocol extension to which they belong.  Protocol extensions must each have a unique name.  Hosts can query each other to discover which extensions they support -- see [[Host Status -> #host-status]] below.

Changed lines 77-92 from:

!!! Neighbour Connections

Ripple nodes may connect when one or both accept the other's obligations as valuable.  Connected nodes are said to be neighbours
.  A ''neighbour connection'' is a relationship defined by an agreement to participate in Ripple transactions as neighbours, and does not refer to the messaging connection that may exist from time to time between the neighbouring nodes' hosts, and over which the neighbour relationship takes place.

The Ripple Payment Protocol involves nodes issuing and accepting obligations of a certain value to and from their neighbours, but doesn't specify how these obligations are recorded or what the terms or limits of these obligations are.  Neighbours must agree on an accounting system that will approve potential transactions and record the balance of committed transactions between them.  One such system is the Ripple Account Protocol.

A neighbour connection consists of nothing other than one or more accounts between the neighbours.  The minimal set of data that must be known by two neighbouring nodes in order to participate in Ripple payments is:

* a Ripple ID for each node
* an account ID
* the unit of account
* an authentication key for each node

The JSON data structure for an account is:

to:
[[#host-status]]
'''Host Status'''

At any time they are connected, a host may request another for the status of its protocol support by sending a @@host-status@@ message
.
Changed lines 84-95 from:
  "account": {
    "account-id": (string),
    "unit": (URI),
    "account-type": (string),
    "initiator": {
      "node-id": (Ripple ID),
      "key": (public key data structure)
    },
    "partner": {
      "node-id": (Ripple ID),
      "key": (public key data structure)
    },
to:
  "host-status"
Changed lines 88-98 from:
The roles of @@initiator@@ node and @@partner@@ node are determined at account creation time, with the node making the initial account offer being deemed the @@initiator@@.  These roles stay constant for the life of the account, allowing either node to change its node ID. 

The @@account-type@@ field allows different types of accounts to integrate into the Ripple network.  Each account type can specify alterations to the basic protocol.  See [[AccountExtension]].

[[#account-messages]]
'''Account Messages'''

There are two primary account messages: @@account-request@@ and @@account-set@@.

An @@account-request@@ is to request a new account, or to request a change to one or more account fields that could not be dictated unilaterally by the requesting node.  An @@account-request@@ must be signed unless the request could in other circumstances be imposed unilaterally by the node receiving the request.  Otherwise, the requesting node must indicate that it gives permission to make the requested changes by signing the @@account-request@@, which allows this permission to be verified at a later date.  If a node receives an unsigned message that it feels ought to be signed, it should reply with a ''Message must be signed'' error.  An implementation may decide to simply sign every @@account-request@@
.
to:
The host receiving such a message must reply immediately with a list of protocol versions and extensions to each that it understands.
Changed lines 92-99 from:
  "account-request": {
    "request-id": (integer),
    "account": {
      "account-id": (string),
      (remaining account data structure containing requested field values)
    },
    "note": (string - optional)
  }
to:
  "host-status": [
    {
      "version": "1",
      "extensions": [
       "ripple-routing",
   
  "ripple-channel",
        "ripple-account",
     ]
   
}
  ]
Changed lines 105-110 from:
To avoid overlap, the @@initiator@@ node uses odd request IDs, and the @@partner@@ node uses even request IDs.  Only those account fields that contain new, non-default values, or are to be changed need to be included.

The @@account-set@@ message is to confirm a new account, accept
the changes requested in an @@account-request@@, or to unilaterally declare changes to account fields where permitted.  While any arrangement may be negotiated between nodes by trial and error, in general, a node may unilaterally dictate values for its own @@node-id@@, @@routing-id@@, and @@key@@, as well as decreases to either node's credit limit.  Credit limit increases would generally require an @@account-request@@, although when it contains an increase to the other node's limit, the request is better understood as an offer.

An @@account-set@@ must always be signed
.
to:

!!! Neighbour Connections

Ripple nodes may connect when one or both accept
the other's obligations as valuable.  Connected nodes are said to be neighbours.  A ''neighbour connection'' is a relationship defined by an agreement to participate in Ripple transactions as neighbours, and does not refer to the messaging connection that may exist from time to time between the neighbouring nodes' hosts, and over which the neighbour relationship takes place.

The Ripple Payment Protocol involves nodes issuing
and accepting obligations of a certain value to and from their neighbours, but doesn't specify how these obligations are recorded or what the terms or limits of these obligations are.  Neighbours must agree on an accounting system that will approve potential transactions and record the balance of committed transactions between themOne such system is the Ripple Account Protocol.

A neighbour connection consists of nothing other than one or more accounts between the neighbours.  The minimal set of data that must be known by two neighbouring nodes in order to participate in Ripple payments is:

* a Ripple ID for each node
* an account ID
* the unit of account
* an authentication key for each node

The JSON data structure for an account is:

Changed lines 123-128 from:
  "account-set": {
    "request-id": (integer - only present on responses to account-requests),
    "timestamp": (date/time string),
    "account": {
 
    "account-id": (string),
      (remaining account data
structure containing requested field values)
to:
  "account": {
    "account-id": (string),
    "unit": (URI),
    "
account-type": (string),
    "initiator": {
 
     "node-id": (Ripple ID),
     "key": (public key data structure)
Changed lines 131-134 from:
  }
to:
    "partner": {
      "node-id": (Ripple ID),
      "key": (public key data structure)
   
},
Changed lines 138-154 from:
The request ID is only necessary when the @@account-set@@ refers to an earlier request.  In that case, the account fields must be identical to those in the earlier @@account-request@@ with the same request ID.

The timestamp establishes
the exact time, measured in [[connection time -> #connection-time]], that the changes to the account fields take effect.

Account messages, other than at account-creation time, should only alter one
account field at a time unless two or more fields must be altered in atomic fashion.

[[#establishing-an-account]]
'''Establishing an Account'''

Accounts are established by a signed @@account-request@@ message sent between potential or existing neighbours containing the basic information for the account:

* a request ID
* an
account ID
* the offering node's network ID
* the units of
account

Example:
to:
The roles of @@initiator@@ node and @@partner@@ node are determined at account creation time, with the node making the initial account offer being deemed the @@initiator@@.  These roles stay constant for the life of the account, allowing either node to change its node ID. 

The @@
account-type@@ field allows different types of accounts to integrate into the Ripple network.  Each account type can specify alterations to the basic protocol.  See [[AccountExtension]].

[[#account-messages]]
'''Account Messages'''

There are two primary account messages: @@account-request@@ and @@account-set@@.

An @@account-request@@ is to request a new account, or to request a change to one or more
account fields that could not be dictated unilaterally by the requesting node.  An @@account-request@@ must be signed unless the request could in other circumstances be imposed unilaterally by the node receiving the request.  Otherwise, the requesting node must indicate that it gives permission to make the requested changes by signing the @@account-request@@, which allows this permission to be verified at a later date.  If a node receives an unsigned message that it feels ought to be signed, it should reply with a ''Message must be signed'' error.  An implementation may decide to simply sign every @@account-request@@.
Changed lines 152-153 from:
   "request-id": 1,
to:
   "request-id": (integer),
Changed lines 154-163 from:
     "account-id": "550e8400-e29b-41d4-a716-446655440000",
      "unit": "urn:ripple:units:CAD",
      "account-type": (...
),
      "initiator": {
        "node-id": "rfugger@ripplepay.com",
        "key": (...),
      },
      "partner": {
        "node-id": "random@example.com",
      }
to:
     "account-id": (string),
      (remaining account data structure containing requested field values)
Changed lines 157-158 from:

    "note": "Let's have an account!"
to:
   "note": (string - optional)
Changed lines 162-206 from:
An affirmative reply means the offer has been understood being held for consideration.  If the offer recipient accepts the offer, his node sends back an @@account-set@@ echoing the request ID and the full account data structure in the request, as well as a timestamp which is the official account creation time.

To indicate that the account has been created, the node receiving the @@account-set@@ responds with an affirmative reply.  If the reply is an error, the account is not created.

[[#identification-of-account-partner]]
'''Identification of Account Partner'''

Ripple has no universal mechanism for positively identifying the owner of another node.  The owner of a node receiving a new account request should confirm the identity of the owner of the requesting node before assigning it a non-zero credit limit.  Even if the node ID in the form ''node@host.com'' of the requesting node is familiar to the request recipient, one must ensure that the transport layer has verified positively by some means that the request actually comes from the correct host and that the host is trustworthy before relying solely on that piece of information.

The requesting node's owner may put secret, personal, or other information that could help the receiving node's owner identify them, such as a message signed with a personal signing key, into the @@note@@ field of the @@account-request@@.

[[#changing-account-data]]
'''Changing Account Data'''

To declare a change to one or more account data fields, a node sends a signed @@account-set@@ message to its account partner.  An affirmative reply by the other node indicates acceptance of those changes.  An error indicates rejection.

To request a change to one or more account data fields, a node sends an @@account-request@@ message.  An affirmative reply here only indicates that the request has been understood and is being held for approval. 

Once the request is approved, the request recipient sends an @@account-set@@ message echoing back the account fields and values and request ID from the @@account-request@@.  An affirmative reply to the @@account-set@@ completes the change.

[[#account-change-errors]]
'''Account Change Errors'''

The following errors allow nodes to negotiate between them what are permissible unilateral changes and what aren't in case of disagreement:

: ''Field change by account-request only'' : Contains path to field that node receiving an @@account-set@@ deems requires an @@account-request@@ to change in the manner requested.

: ''Unilateral declaration preferred'' : Node receiving an @@account-request@@ deems an @@account-set@@ preferable for the requested change.  (Equally valid is to simply accept the request immediately -- perhaps this error is unnecessary?)

[[#adding-new-fields]]
'''Adding New Fields'''

To add a new data field to an account, use @@account-set@@ or @@account-request@@ as appropriate.  If the other node does not understand the field, it will reply with an error, and the field may not be added.

[[#changing-keys]]
'''Changing Keys'''

An account message declaring or requesting a key change should be signed by the old key.  Subsequent signed messages must be signed by the new key.

[[#verifying-account-data]]
'''Verifying Account Data'''

To request a copy of an account partner's account data for verification, send an @@account-verify-request@@ message containing the account ID: 

Example:
to:
To avoid overlap, the @@initiator@@ node uses odd request IDs, and the @@partner@@ node uses even request IDs.  Only those account fields that contain new, non-default values, or are to be changed need to be included.

The @@account-set@@ message is to confirm a new account, accept the changes requested in an @@account-request@@, or to unilaterally declare changes to account fields where permitted.  While any arrangement may be negotiated between nodes by trial and error, in general, a node may unilaterally dictate values for its own @@node-id@@, @@routing-id@@, and @@key@@, as well as decreases to either node's credit limit.  Credit limit increases would generally require an @@account-request@@, although when it contains an increase to the other node's limit, the request is better understood as an offer.

An @@account-set@@ must always be signed.

Changed lines 170-171 from:
  "account-verify-request": {
    "account-id": "550e8400-e29b-41d4-a716-446655440000"
to:
  "account-set": {
    "request-id": (integer - only present on responses to account-requests),
   
"timestamp": (date/time string),
    "account": {
      "account-id": (string),
      (remaining account data structure containing requested field values)
    },
Changed lines 181-182 from:
The immediate reply must contain the complete account data structure of the node receiving the @@account-verify-request@@ as well as a timestamp:
to:
The request ID is only necessary when the @@account-set@@ refers to an earlier request.  In that case, the account fields must be identical to those in the earlier @@account-request@@ with the same request ID.

The
timestamp establishes the exact time, measured in [[connection time -> #connection-time]], that the changes to the account fields take effect.

Account messages, other than at account-creation time, should only alter one account field at a time unless two or more fields must be altered in atomic fashion.

[[#establishing-an-account]]
'''Establishing an Account'''

Accounts are established by a signed @@account-request@@ message sent between potential or existing neighbours containing the basic information for the account
:

* a request ID
* an account ID
* the offering node's network ID
* the units of account

Changed lines 200-201 from:
  "account-verify": {
    "timestamp": "2006-11-07 02:11:28.401000",
to:
  "account-request": {
    "request-id": 1,
Changed lines 204-205 from:
     (...)
    }
to:
     "account-id": "550e8400-e29b-41d4-a716-446655440000",
     "unit": "urn:ripple:units:CAD",
      "account-type": (...),
      "initiator": {
        "node-id": "rfugger@ripplepay.com",
        "key": (...),
     
},
      "partner": {
        "node-id": "random@example.com",
      }
    },

    "note": "Let's have an account!"
Changed lines 221-227 from:
Neither message nor reply must be signed.

[[#account-history]]
'''Account History'''

To request from an account partner a list of every signed message that has changed the value of an account field over a certain period, send an @@account-history-request@@:

to:
An affirmative reply means the offer has been understood being held for consideration.  If the offer recipient accepts the offer, his node sends back an @@account-set@@ echoing the request ID and the full account data structure in the request, as well as a timestamp which is the official account creation time.

To indicate that the account has been created, the node receiving the @@account-set@@ responds with an affirmative reply.  If the reply is an error, the account is not created.

[[#identification-of-account-partner]]
'''Identification of Account Partner'''

Ripple has no universal mechanism for positively identifying the owner of another node.  The owner of a node receiving a new account request should confirm the identity of the owner of the requesting node before assigning it a non-zero credit limit.  Even if the node ID in the form ''node@host.com'' of the requesting node is familiar to the request recipient, one must ensure that the transport layer has verified positively by some means that the request actually comes from the correct host and that the host is trustworthy before relying solely on that piece of information.

The requesting node's owner may put secret, personal, or other information that could help the receiving node's owner identify them, such as a message signed with a personal signing key, into the @@note@@ field of the @@account-request@@.

[[#changing-account-data]]
'''Changing Account Data'''

To declare a change to one or more account data fields, a node sends a signed @@account-set@@ message to its account partner.  An affirmative reply by the other node indicates acceptance of those changes.  An error indicates rejection.

To request a change to one or more account data fields, a node sends an @@account-request@@ message.  An affirmative reply here only indicates that the request has been understood and is being held for approval. 

Once the request is approved, the request recipient sends an @@account-set@@ message echoing back the account fields and values and request ID from the @@account-request@@.  An affirmative reply to the @@account-set@@ completes the change.

[[#account-change-errors]]
'''Account Change Errors'''

The following errors allow nodes to negotiate between them what are permissible unilateral changes and what aren't in case of disagreement:

: ''Field change by account-request only'' : Contains path to field that node receiving an @@account-set@@ deems requires an @@account-request@@ to change in the manner requested.

: ''Unilateral declaration preferred'' : Node receiving an @@account-request@@ deems an @@account-set@@ preferable for the requested change.  (Equally valid is to simply accept the request immediately -- perhaps this error is unnecessary?)

[[#adding-new-fields]]
'''Adding New Fields'''

To add a new data field to an account, use @@account-set@@ or @@account-request@@ as appropriate.  If the other node does not understand the field, it will reply with an error, and the field may not be added.

[[#changing-keys]]
'''Changing Keys'''

An account message declaring or requesting a key change should be signed by the old key.  Subsequent signed messages must be signed by the new key.

[[#verifying-account-data]]
'''Verifying Account Data'''

To request a copy of an account partner's account data for verification, send an @@account-verify-request@@ message containing the account ID: 

Changed lines 268-270 from:
  "account-history-request": {
    "starting": "2006-01-01 00:00:00.000000",
    "ending": "2006-11-07 02:11:28.401000
"
to:
  "account-verify-request": {
    "account-id": "550e8400-e29b-41d4-a716-446655440000"
Changed lines 274-277 from:
If the "starting" field is omitted, messages from beginning of the account should be included in the reply.  If the "ending" field is omitted, messages up to the present should be included.

The reply is as follows
:
to:
The immediate reply must contain the complete account data structure of the node receiving the @@account-verify-request@@ as well as a timestamp:

Example:
Changed lines 279-284 from:
  "account-history": [
    (a chronological order of signed messages sent and received over
    this account during the requested period that have changed a piece
    of shared account data, in the format they were originally sent or
    received, including signatures)
  ]
to:
  "account-verify": {
    "timestamp": "2006-11-07 02:11:28.401000",
    "account": {
 
    (...)
    }
  }
Changed lines 288-294 from:
This account history may be used as an audit to find the source of any data discrepancies between partners.  This same output may also be taken for each account by a node owner from her own node in order to backup account data or move a node to a different host.

[[#closing
-an-account]]
'''Closing an Account'''

To close an account, either party may send an
@@account-close@@ message containing the ID of the account to be closed:
to:
Neither message nor reply must be signed.

[[#account-history]]
'''Account History'''

To request from an account partner a list
of every signed message that has changed the value of an account field over a certain period, send an @@account-history-request@@:
Changed lines 298-300 from:
  "account-close": {
    "request-id": 14590,
 
  "account-id": "550e8400-e29b-41d4-a716-446655440000"
to:
  "account-history-request": {
    "starting": "2006-01-01 00:00:00.000000",
   "ending": "2006-11-07 02:11:28.401000"
Changed lines 305-328 from:
An affirmative reply indicates assent to close the account.  An error indicates refusal.


!!! Payments

To allow payments between two nodes that aren't neighbours, Ripple propagates value account-by-account along one or more paths of accounts in the network connecting payer and recipient.

The basic payment process consists of
:

# Initializing payment between the payer and recipient nodes
# Preparing the paths to commit the transaction
# Committing the transaction

[[#requesting-payment]]
'''Requesting Payment'''

A node wishing to receive a payment from another node may initiate contact with the potential payer node by sending a @@payment-request@@ message to that node containing:

* unique ID for the payment
* amount
* units
* payment recipient's node's network address
* an explanatory note

to:
If the "starting" field is omitted, messages from beginning of the account should be included in the reply.  If the "ending" field is omitted, messages up to the present should be included.

The reply is as follows
:
Changed lines 311-317 from:
  "payment-request": {
    "payment-id": (string),
    "amount": (decimal),
    "unit": (URI),
    "recipient-node-id": (Ripple ID),
    "note": (string)
  }
to:
  "account-history": [
    (a chronological order of signed messages sent and received over
    this account during the requested period that have changed a piece
    of shared account data, in the format they were originally sent or
    received, including signatures)
  ]
Changed lines 320-333 from:
The @@payment-request@@ may be followed by an @@payment-init@@ message from the potential payer, or ignored.

The @@payment-request@@ message may be authorized by signing it with a certain key, contained in the
node owner's smart card, for example, for point-of-sale scenarios where the buyer is unable to communicate directly with his or her node.  (Ideally, the smart card would display the payment amount and units to the buyer for approval, otherwise he or she must trust that the seller's terminal displays the same amount as it is asking the smart card to authorize in the @@payment-request@@ message.)

[[#initializing-payment]]
'''Initializing Payment'''

The payer node contacts recipient node and communicates the following in a @@payment-init@@ message
:

* unique ID for the payment
* amount to be paid to recipient
* units of payment
* some explanatory text to the recipient

to:
This account history may be used as an audit to find the source of any data discrepancies between partners.  This same output may also be taken for each account by a node owner from her own node in order to backup account data or move a node to a different host.

[[#closing-an-account]]
'''Closing an Account'''

To close an account, either party may send an @@account-close@@ message containing
the ID of the account to be closed:

Example:
Changed lines 330-334 from:
  "payment-init": {
    "payment-id": (string),
    "amount": (decimal),
   
"units": (URI),
    "note": (string)
to:
  "account-close": {
    "request-id": 14590,
    "account-id": "550e8400-e29b-41d4-a716-446655440000"
Changed lines 337-347 from:
When generating @@payment-id@@s, nodes should make every effort to ensure they are globally unique in the Ripple network, although this is not strictly necessary for the system to function.  Since the @@payment-id@@ field may be an arbitrary string, this shouldn't be too difficult by following a convention such as appending the precise date & time (UTC) to each ID.

The recipient may accept
the @@payment-init@@ with an affirmative reply containing a @@payment-accept@@ message with the following data:

* payment ID
* amount to be paid to recipient
* units of
payment
* payer's explanatory text echoed back
* recipient's authentication key for payment (used to sign receipts)
* public-key certificate establishing recipient's identity to the payer

to:
An affirmative reply indicates assent to close the account.  An error indicates refusal.


!!! Payments

To allow payments between two nodes that aren't neighbours, Ripple propagates value account-by-account along one or more paths of accounts in the network connecting payer and recipient.

The basic payment process consists of:

# Initializing payment between the payer and recipient nodes
# Preparing the paths
to commit the transaction
# Committing
the transaction

[[#requesting-
payment]]
'''Requesting Payment'''

A node wishing to receive
a payment from another node may initiate contact with the potential payer node by sending a @@payment-request@@ message to that node containing:

* unique ID for the payment
* amount
* units
* payment recipient's node's network address
* an explanatory note

Changed line 363 from:
  "payment-accept": {
to:
  "payment-request": {
Changed lines 366-369 from:
   "units": (URI),
    "note": (string),
    "recipient-receipt-key": (public key data structure),
    "recipient-certificate": (certificate data structure
)
to:
   "unit": (URI),
    "recipient-node-id": (Ripple ID),
    "note": (string)
Changed lines 373-395 from:
This must be signed by the recipient's identifying certificate key, whose certificate identifies the recipient in a way acceptable to the payer, such as being issued (i.e., signed) by an authority recognized by the payer.  This message serves as evidence that the recipient participated in the transaction.  Thus the signature of the recipient's receipt key on the payment receipts can be irrevocably connected the recipient, proving that the payment was indeed received.  The explanatory text can contain text linking the payment to a real-world exchange of goods or services, such as "Payment for auction item #12345".

The recipient may reject the @@payment-init@@ with an error code.

[[#making
-promises]]
'''Making Promises (Commit-Request)'''

To prepare
the payment paths, the payer sends a @@promise@@ message to the first node on each path, representing its commitment to redeem a valid receipt that can be authenticated with the promise's authentication key up to the amount of credit indicated on the receipt, if presented before the stated deadline.

* payment ID
* path ID
* amount to be held for payment, in path units
* ID of account to be made part of path by this promise being passed
* amount to be held for payment, in account units
* a routing onion (optional)
* a time limit to reach the
recipient, in connection time
* promise penalty deadline, in connection time
* daily penalty rate if receipt or path-cancel not received before the penalty deadline
* promise final deadline, in connection time, after which promise expires
* the payer's receipt authentication key for this payment path
* the recipient's receipt authentication key for this payment path
* a timestamp to indicate the time the promise came into effect, in connection time

to:
The @@payment-request@@ may be followed by an @@payment-init@@ message from the potential payer, or ignored.

The @@payment-request@@ message may be authorized by signing it with a certain key, contained in the node owner's smart card, for example, for point-of-sale scenarios where the buyer is unable to communicate directly with his or her node.  (Ideally,
the smart card would display the payment amount and units to the buyer for approval, otherwise he or she must trust that the seller's terminal displays the same amount as it is asking the smart card to authorize in the @@payment-request@@ message.)

[[#initializing-payment]]
'''Initializing Payment'''

The payer node contacts recipient node and communicates the following in a @@payment
-init@@ message:

* unique ID for
the payment
* amount to be paid to recipient
* units of payment
* some explanatory text to the
recipient
Changed line 389 from:
  "promise": {
to:
  "payment-init": {
Deleted lines 390-392:
   "path-id": [(ordered list of strings)],
    "path-amount": (decimal),
    "account-id": (string),
Changed lines 392-399 from:
   "onion": (routing onion data structure),
   
"ttl": (date/time string),
    "penalty-deadline": (date/time string),
    "penalty-rate": (decimal),
    "deadline": (date/time string),
    "payer-receipt-key": (public key data structure),
    "recipient-receipt-key": (public key data structure),
    "timestamp": (date/time
string)
to:
   "units": (URI),
 
"note": (string)
Added line 395:
}
Changed lines 398-414 from:
Since a promise must be fulfilled if a valid @@receipt@@ is presented, it must effectively hold the required amount on the designated account in such a way that no other transaction may invalidate the payment.

Each node that receives a promise message updates its fields and passes it on to the next node in
the path, as determined by data gleaned from the routing onion and/or by extension fields that inform a routing system defined in a protocol extension.  At each step, the promise message is signed to the next node by the passing node's authentication key.  This serves to establish the integrity and non-repudiability of the promise.

The @@path-id@@ is defined as an ordered list of strings to accommodate routing systems that may use such lists to permit paths to fork into multiple directions while still allowing previous intermediaries in the path to recognize these subpaths and prevent loops from forming.  Therefore, a path with ID @@[ A, B ]@@ must be recognized as a forked continuation of the path the same @@payment-id@@ and @@path-id@@ @@[ A ]@@.  For the purposes of @@promise@@ and @@receipt@@ routing, these are the same path.

The @@path-amount@@ is invented by the payer and given in arbitrary units (''path units'') particular to each path.  This figure gives each intermediary a reference against which to know the value of the @@receipt@@ message that commits the transaction, which will contain a @@path-amount@@ less than or equal to the @@promise@@ @@path-amount@@. 

The @@ttl@@ (''time-to-live'') field allows the payer to specify a deadline for the @@promise@@ to reach the recipient.  If it should fail to reach the recipient by that time, the latest receiver of the @@promise@@ should release the sender from its promise, and so on back to the payer (see [[Releasing Promises -> #releasing-promises]] below).  This field allows the payer to reasonably limit the amount of time it wishes to wait to see whether the path is viable.

The @@penalty-deadline@@ is the time after which the promising node may begin charging a penalty to its partner for having to hold credit it could be using for payment.  The penalty is charged continuously at the daily rate specified.  Intermediaries should always set a shorter deadline and higher penalty rate on promises out than they have received on promises in, to ensure that they are compensated for overdue @@receipts@@.  This provides incentive for the recipient to ensure quick completion or cancellation of each promise path, without requiring hard-and-fast deadlines to come into play so soon that minor delays relaying the receipt back along the path spawn major disputes.

[[#finalizing-payment]]
'''Finalizing the Payment'''

As the recipient receives each @@promise@@, it reports it back to the payer with a @@promise-received@@
:
to:
When generating @@payment-id@@s, nodes should make every effort to ensure they are globally unique in the Ripple network, although this is not strictly necessary for the system to function.  Since the @@payment-id@@ field may be an arbitrary string, this shouldn't be too difficult by following a convention such as appending the precise date & time (UTC) to each ID.

The recipient may accept the @@payment-init@@ with an affirmative reply containing a @@payment-accept@@ message with the following data
:
Changed lines 403-406 from:
* path ID
* recipient's deadline for accepting the receipts for these paths, in connection time
* final amount of promise in payment units as computed by recipient
to:
* amount to be paid to recipient
* units of payment
* payer's explanatory text echoed back
* recipient's authentication key for payment (used to sign receipts)
* public-key certificate establishing
recipient's identity to the payer
Changed line 411 from:
  "promise-received": {
to:
  "payment-accept": {
Changed lines 413-415 from:
   "path-id": [(ordered list of strings)],
   
"deadline": (date/time string),
    "amount": (decimal)
to:
   "amount": (decimal),
 
"units": (URI),
    "note": (string),
    "recipient-receipt-key": (public key data structure),
    "recipient-certificate": (certificate data structure
)
Changed lines 422-427 from:
The recipient's receipt deadline to the payer should be well before the penalty deadline on the @@promise@@ the recipient received.

The recipient can cancel the transaction at any time
by sending the payer a @@payment-cancel@@ and releasing its neighbours from their promises with a @@promise-release@@ (see [[Releasing Promises -> #releasing-promises]]).  The payer can cancel the transaction by sending the recipient a @@payment-cancel@@, informing it that it can release its neighbours from their promises.  Released promises should be propagated back down each payment path to free up those funds for other payments.

When the payer receives a satisfactory set of
@@promise-received@@ messages totaling the payment amount or greater, it generates one @@receipt@@ message per @@promise-received@@s, authenticates it individually with the corresponding @@payer-receipt-key@@, and sends it to the recipient before the deadline for doing so:
to:
This must be signed by the recipient's identifying certificate key, whose certificate identifies the recipient in a way acceptable to the payer, such as being issued (i.e., signed) by an authority recognized by the payer.  This message serves as evidence that the recipient participated in the transaction.  Thus the signature of the recipient's receipt key on the payment receipts can be irrevocably connected the recipient, proving that the payment was indeed received.  The explanatory text can contain text linking the payment to a real-world exchange of goods or services, such as "Payment for auction item #12345".

The recipient may reject the
@@payment-init@@ with an error code.

[[#making-promises]]
'''Making Promises (Commit-Request)'''

To prepare the payment paths, the payer sends a
@@promise@@ message to the first node on each path, representing its commitment to redeem a valid receipt that can be authenticated with the promise's authentication key up to the amount of credit indicated on the receipt, if presented before the stated deadline.
Changed lines 433-434 from:
* amount for this path, in path units
to:
* amount to be held for payment, in path units
* ID of account to be made part of path by this promise being passed
* amount to be held for payment, in account units
* a routing onion (optional)
* a time limit to reach the recipient, in connection time
* promise penalty deadline, in connection time
* daily penalty rate if receipt or path-cancel not received before the penalty deadline
* promise final deadline, in connection time, after which promise expires
* the payer's receipt authentication key for this payment path
* the recipient's receipt authentication key for this payment path
* a timestamp to indicate the time the promise came into effect, in connection time

Changed line 447 from:
  "receipt": {
to:
  "promise": {
Changed lines 450-460 from:
   "path-amount": (decimal)
to:
   "path-amount": (decimal),
    "account-id": (string),
    "amount": (decimal),
    "onion": (routing onion data structure),
    "ttl": (date/time string),
    "penalty-deadline": (date/time string),
    "penalty-rate": (decimal),
    "deadline": (date/time string),
    "payer-receipt-key": (public key data structure),
    "recipient-receipt-key": (public key data structure),
    "timestamp": (date/time string
)
Added lines 464-515:
Since a promise must be fulfilled if a valid @@receipt@@ is presented, it must effectively hold the required amount on the designated account in such a way that no other transaction may invalidate the payment.

Each node that receives a promise message updates its fields and passes it on to the next node in the path, as determined by data gleaned from the routing onion and/or by extension fields that inform a routing system defined in a protocol extension.  At each step, the promise message is signed to the next node by the passing node's authentication key.  This serves to establish the integrity and non-repudiability of the promise.

The @@path-id@@ is defined as an ordered list of strings to accommodate routing systems that may use such lists to permit paths to fork into multiple directions while still allowing previous intermediaries in the path to recognize these subpaths and prevent loops from forming.  Therefore, a path with ID @@[ A, B ]@@ must be recognized as a forked continuation of the path the same @@payment-id@@ and @@path-id@@ @@[ A ]@@.  For the purposes of @@promise@@ and @@receipt@@ routing, these are the same path.

The @@path-amount@@ is invented by the payer and given in arbitrary units (''path units'') particular to each path.  This figure gives each intermediary a reference against which to know the value of the @@receipt@@ message that commits the transaction, which will contain a @@path-amount@@ less than or equal to the @@promise@@ @@path-amount@@. 

The @@ttl@@ (''time-to-live'') field allows the payer to specify a deadline for the @@promise@@ to reach the recipient.  If it should fail to reach the recipient by that time, the latest receiver of the @@promise@@ should release the sender from its promise, and so on back to the payer (see [[Releasing Promises -> #releasing-promises]] below).  This field allows the payer to reasonably limit the amount of time it wishes to wait to see whether the path is viable.

The @@penalty-deadline@@ is the time after which the promising node may begin charging a penalty to its partner for having to hold credit it could be using for payment.  The penalty is charged continuously at the daily rate specified.  Intermediaries should always set a shorter deadline and higher penalty rate on promises out than they have received on promises in, to ensure that they are compensated for overdue @@receipts@@.  This provides incentive for the recipient to ensure quick completion or cancellation of each promise path, without requiring hard-and-fast deadlines to come into play so soon that minor delays relaying the receipt back along the path spawn major disputes.

[[#finalizing-payment]]
'''Finalizing the Payment'''

As the recipient receives each @@promise@@, it reports it back to the payer with a @@promise-received@@:

* payment ID
* path ID
* recipient's deadline for accepting the receipts for these paths, in connection time
* final amount of promise in payment units as computed by recipient

[@
{
  "promise-received": {
    "payment-id": (string),
    "path-id": [(ordered list of strings)],
    "deadline": (date/time string),
    "amount": (decimal)
  }
}
@]

The recipient's receipt deadline to the payer should be well before the penalty deadline on the @@promise@@ the recipient received.

The recipient can cancel the transaction at any time by sending the payer a @@payment-cancel@@ and releasing its neighbours from their promises with a @@promise-release@@ (see [[Releasing Promises -> #releasing-promises]]).  The payer can cancel the transaction by sending the recipient a @@payment-cancel@@, informing it that it can release its neighbours from their promises.  Released promises should be propagated back down each payment path to free up those funds for other payments.

When the payer receives a satisfactory set of @@promise-received@@ messages totaling the payment amount or greater, it generates one @@receipt@@ message per @@promise-received@@s, authenticates it individually with the corresponding @@payer-receipt-key@@, and sends it to the recipient before the deadline for doing so:

* payment ID
* path ID
* amount for this path, in path units

[@
{
  "receipt": {
    "payment-id": (string),
    "path-id": [(ordered list of strings)],
    "path-amount": (decimal)
  }
@]

Changed lines 20-21 from:
to:
* how two hosts ensure they are both using the same version of this protocol
Changed line 98 from:
   "authority": ("shared"/"initiator"),
to:
   "account-type": (string),
Changed lines 112-113 from:
The @@authority@@ determines who will maintain records for the account.  The usual arrangement is @@shared@@, which requires some more account fields (see [[AccountExtension]]).  Alternatively, Ripple may be used on top of an existing electronic account that stores balances, credit limits, etc., which must be controlled by the @@initiator@@, and for which this minimal set of account fields is adequate.
to:
The @@account-type@@ field allows different types of accounts to integrate into the Ripple network.  Each account type can specify alterations to the basic protocol.  See [[AccountExtension]].
Changed line 178 from:
     "authority": "initiator",
to:
     "account-type": (...),
Added line 177:
     "authority": "initiator",
Changed line 97 from:
   "account-authority": ("shared"/"initiator"),
to:
   "authority": ("shared"/"initiator"),
Changed lines 111-112 from:
The @@account-authority@@ determines who will maintain records for the account.  The usual arrangement is @@shared@@, which requires some more account fields (see [[AccountExtension]]).  Alternatively, Ripple may be used on top of an existing electronic account that stores balances, credit limits, etc., which must be controlled by the @@initiator@@, and for which this minimal set of account fields is adequate.
to:
The @@authority@@ determines who will maintain records for the account.  The usual arrangement is @@shared@@, which requires some more account fields (see [[AccountExtension]]).  Alternatively, Ripple may be used on top of an existing electronic account that stores balances, credit limits, etc., which must be controlled by the @@initiator@@, and for which this minimal set of account fields is adequate.
Added line 97:
   "account-authority": ("shared"/"initiator"),
Changed lines 109-110 from:
The roles of @@initiator@@ node and @@partner@@ node are determined at account creation time, with the node making the initial account offer being deemed the @@initiator@@.  These roles stay constant for the life of the account, allowing either node to change its node ID.
to:
The roles of @@initiator@@ node and @@partner@@ node are determined at account creation time, with the node making the initial account offer being deemed the @@initiator@@.  These roles stay constant for the life of the account, allowing either node to change its node ID

The @@account-authority@@ determines who will maintain records for the account.  The usual arrangement is @@shared@@, which requires some more account fields (see [[AccountExtension]]).  Alternatively, Ripple may be used on top of an existing electronic account that stores balances, credit limits, etc., which must be controlled by the @@initiator@@, and for which this minimal set of account fields is adequate
.
February 02, 2007, at 08:31 PM by ryan - fixed example message to reflect proper account data structure
Changed lines 40-45 from:
   "nodes": [
      {
 
       "node-id": "rfugger@ripplepay.com",
        "limit": 500
     
}
    ]
to:
   "initiator": {
      "limit": 500
    }
December 11, 2006, at 08:51 PM by ryan - removed search ID, specified unique payment ID, multiple receipts per promise
Added lines 368-369:
When generating @@payment-id@@s, nodes should make every effort to ensure they are globally unique in the Ripple network, although this is not strictly necessary for the system to function.  Since the @@payment-id@@ field may be an arbitrary string, this shouldn't be too difficult by following a convention such as appending the precise date & time (UTC) to each ID.
Deleted line 401:
* search ID
Changed lines 419-420 from:
   "search-id": (integer),
    "path-id": (string
),
to:
   "path-id": [(ordered list of strings)],
Changed lines 438-439 from:
The @@search-id@@ allows the payer to send of multiple sets of promises down different potential paths without interfering with each other.  An intermediary may use the same credit hold on an account to cover promises with the same @@payment-id@@ but different @@search-ids@@.  In the end, the payer may only issue receipts for a single @@search-id@@, and the rest must be released.  By issuing multiple sets of promises, the payer increases the chance of more quickly finding a useable set of paths, and, if multiple useable sets are found, the payer may choose the cheapest among them.
to:
The @@path-id@@ is defined as an ordered list of strings to accommodate routing systems that may use such lists to permit paths to fork into multiple directions while still allowing previous intermediaries in the path to recognize these subpaths and prevent loops from forming.  Therefore, a path with ID @@[ A, B ]@@ must be recognized as a forked continuation of the path the same @@payment-id@@ and @@path-id@@ @@[ A ]@@.  For the purposes of @@promise@@ and @@receipt@@ routing, these are the same path.
Deleted line 451:
* search ID
Changed lines 460-461 from:
   "search-id": (integer),
    "path-id": (string
),
to:
   "path-id": [(ordered list of strings)],
Deleted line 473:
* search ID
Changed lines 481-482 from:
   "search-id": (integer),
    "path-id": (string
),
to:
   "path-id": [(ordered list of strings)],
Added lines 488-489:
The recipient redeems receipts with its neighbours that have issued promises to do so.  Each receipt may only partially redeem the value of a single promise, and multiple receipts may be redeemed for a single promise.  The unredeemed portion of the promise must be released before the penalty deadline or the penalty must be paid.
Changed lines 449-450 from:
If the recipient receives promises in a single @@search-id@@ set totalling (in @@account-units@@, after conversion by the recipient) an amount greater than or equal to the payment amount designated in the @@payment-init@@ message, it sends the payer a @@promise-bundle@@ message containing:
to:
As the recipient receives each @@promise@@, it reports it back to the payer with a @@promise-received@@:
Added line 453:
* path ID
Changed lines 455-458 from:
* for each promise received:
  * path ID
 
* final amount of promise in payment units as computed by recipient
to:
* final amount of promise in payment units as computed by recipient
Changed line 459 from:
  "promise-bundle": {
to:
  "promise-received": {
Added line 462:
   "path-id": (string),
Changed lines 464-472 from:
   "promises": [
      {
        "path-id":
(string),
        "amount": (decimal)
      }, {
        "path-id": (string),
        "amount": (decimal)
      }, (etc.)
    ]
to:
   "amount": (decimal)
Changed lines 469-470 from:
The recipient's receipt deadline to the payer should be well before the penalty deadline on any promise received.
to:
The recipient's receipt deadline to the payer should be well before the penalty deadline on the @@promise@@ the recipient received.
Changed lines 473-474 from:
When the payer receives satisfactory @@promise-bundle@@, it generates @@receipt@@ messages corresponding to the @@promise@@s in it – one receipt per @@promise@@/path – and totalling the payment amount, authenticates them individually with each path's @@payer-receipt-key@@, and sends them each to the recipient:
to:
When the payer receives a satisfactory set of @@promise-received@@ messages totaling the payment amount or greater, it generates one @@receipt@@ message per @@promise-received@@s, authenticates it individually with the corresponding @@payer-receipt-key@@, and sends it to the recipient before the deadline for doing so:
Changed lines 449-450 from:
If the recipient receives promises in a single @@search-id@@ set totalling (in @@account-amounts, after conversion by the recipient) an amount greater than or equal to the payment amount designated in the @@payment-init@@ message, it sends the payer a @@promise-bundle@@ message containing:
to:
If the recipient receives promises in a single @@search-id@@ set totalling (in @@account-units@@, after conversion by the recipient) an amount greater than or equal to the payment amount designated in the @@payment-init@@ message, it sends the payer a @@promise-bundle@@ message containing:
Added lines 1-500:
!!Ripple Payment Protocol

[[PaymentProtocolWorkPage]]

[[#messaging]]
!!! Messaging

The Ripple network consists of software agents called ''nodes'' connected together pairwise where one or both accept the other's obligations as valuable.  These abstract connections are manifested over messaging connections between hosts, each of which may host multiple nodes. 

[[#binding-to-a-transport-layer]]
'''Binding to a Message Transport Layer'''

A Ripple transport layer binding must specify the following:

* how hosts open and close connections to each other
* how the connection is secured
* how nodes are identified
* how connected hosts address host messages to each other, and how nodes on those hosts address node messages to each other
* how Ripple messaging semantics are implemented (see [[Messaging Semantics -> #messaging-semantics]] below).

[[#messaging-semantics]]
'''Messaging Semantics'''

A message transport layer must distinguish between three message types: @@message@@, @@reply@@, and @@error@@.  Each Ripple @@message@@ has a unique ID within the host-level connection, and must be immediately responded to by either a @@reply@@ or an @@error@@ with the same ID upon receipt.  This serves to establish that the message was received and was either understood (@@reply@@), or deemed somehow malformed or otherwise inappropriate as detailed by an error code and message (@@error@@).  The ID may consist of one or more fields.

Replies and errors may carry any data that a regular message may carry.  In addition, error messages must carry an error code.

In general, nodes need not wait for the reply or error to send another message.

[[#message-syntax]]
'''Message Syntax'''

Ripple messages carried within the transport layer are in [[JSON textual format -> http://json.org/]].  For example:

[@
{
  "account-request": {
    "request-id": 16504,
    "account-id": "550e8400-e29b-41d4-a716-446655440000",
    "nodes": [
      {
        "node-id": "rfugger@ripplepay.com",
        "limit": 500
      }
    ]
  }
}
@]

The indentation and line breaks are for readability in this document only.  The actual messages themselves do not have significant whitespace other than described in the [[JSON specification -> http://www.ietf.org/rfc/rfc4627.txt]].

[[#extensibility]]
'''Extensibility'''

Protocol extensions may add custom fields to Ripple messages, as well as defining their own host and/or node messages.  Nonstandard extensions should take care not to duplicate field names of other extensions, by, for example, giving their field names a short common prefix that identifies the protocol extension to which they belong.


!!! Host Messages

Certain messages are sent to a host, rather than to an individual node on a host.

[[#connection-time]]
'''Connection Time'''

When a connection between two Ripple hosts is established, the host accepting the conection must send a @@time@@ message, consisting of its current time, UTC.  (All times in Ripple are UTC.) 

[@
{
  "time": "2006-10-30 18:47:55.356000"
}
@]

The host receiving the time message echoes back its own time message in reply, indicating that it agrees to use the other host's time as the official time for that connection.  If it disagrees, it replies with an error and sends its own time message.  If that time message is rejected, the connection is closed.  There is little reason to disagree with someone's time at the start of a connection, unless you have oustanding open transactions with the other host that are time-sensitive -- simply store the difference from the local host's time and compensate on sent and received messages. 

During the course of the connection, either host may send a time message to the other to verify the time.  If at any point the two hosts fail to agree on the current time, the connection should be closed.

Time messages can be used to discover connection latency.  They can also act as hearbeat messages to verify the connection.


!!! Neighbour Connections

Ripple nodes may connect when one or both accept the other's obligations as valuable.  Connected nodes are said to be neighbours.  A ''neighbour connection'' is a relationship defined by an agreement to participate in Ripple transactions as neighbours, and does not refer to the messaging connection that may exist from time to time between the neighbouring nodes' hosts, and over which the neighbour relationship takes place.

The Ripple Payment Protocol involves nodes issuing and accepting obligations of a certain value to and from their neighbours, but doesn't specify how these obligations are recorded or what the terms or limits of these obligations are.  Neighbours must agree on an accounting system that will approve potential transactions and record the balance of committed transactions between them.  One such system is the Ripple Account Protocol.

A neighbour connection consists of nothing other than one or more accounts between the neighbours.  The minimal set of data that must be known by two neighbouring nodes in order to participate in Ripple payments is:

* a Ripple ID for each node
* an account ID
* the unit of account
* an authentication key for each node

The JSON data structure for an account is:

[@
{
  "account": {
    "account-id": (string),
    "unit": (URI),
    "initiator": {
      "node-id": (Ripple ID),
      "key": (public key data structure)
    },
    "partner": {
      "node-id": (Ripple ID),
      "key": (public key data structure)
    },
}
@]

The roles of @@initiator@@ node and @@partner@@ node are determined at account creation time, with the node making the initial account offer being deemed the @@initiator@@.  These roles stay constant for the life of the account, allowing either node to change its node ID.

[[#account-messages]]
'''Account Messages'''

There are two primary account messages: @@account-request@@ and @@account-set@@.

An @@account-request@@ is to request a new account, or to request a change to one or more account fields that could not be dictated unilaterally by the requesting node.  An @@account-request@@ must be signed unless the request could in other circumstances be imposed unilaterally by the node receiving the request.  Otherwise, the requesting node must indicate that it gives permission to make the requested changes by signing the @@account-request@@, which allows this permission to be verified at a later date.  If a node receives an unsigned message that it feels ought to be signed, it should reply with a ''Message must be signed'' error.  An implementation may decide to simply sign every @@account-request@@.

[@
{
  "account-request": {
    "request-id": (integer),
    "account": {
      "account-id": (string),
      (remaining account data structure containing requested field values)
    },
    "note": (string - optional)
  }
}
@]

To avoid overlap, the @@initiator@@ node uses odd request IDs, and the @@partner@@ node uses even request IDs.  Only those account fields that contain new, non-default values, or are to be changed need to be included.

The @@account-set@@ message is to confirm a new account, accept the changes requested in an @@account-request@@, or to unilaterally declare changes to account fields where permitted.  While any arrangement may be negotiated between nodes by trial and error, in general, a node may unilaterally dictate values for its own @@node-id@@, @@routing-id@@, and @@key@@, as well as decreases to either node's credit limit.  Credit limit increases would generally require an @@account-request@@, although when it contains an increase to the other node's limit, the request is better understood as an offer.

An @@account-set@@ must always be signed.

[@
{
  "account-set": {
    "request-id": (integer - only present on responses to account-requests),
    "timestamp": (date/time string),
    "account": {
      "account-id": (string),
      (remaining account data structure containing requested field values)
    },
  }
}
@]

The request ID is only necessary when the @@account-set@@ refers to an earlier request.  In that case, the account fields must be identical to those in the earlier @@account-request@@ with the same request ID.

The timestamp establishes the exact time, measured in [[connection time -> #connection-time]], that the changes to the account fields take effect.

Account messages, other than at account-creation time, should only alter one account field at a time unless two or more fields must be altered in atomic fashion.

[[#establishing-an-account]]
'''Establishing an Account'''

Accounts are established by a signed @@account-request@@ message sent between potential or existing neighbours containing the basic information for the account:

* a request ID
* an account ID
* the offering node's network ID
* the units of account

Example:
[@
{
  "account-request": {
    "request-id": 1,

    "account": {
      "account-id": "550e8400-e29b-41d4-a716-446655440000",
      "unit": "urn:ripple:units:CAD",
      "initiator": {
        "node-id": "rfugger@ripplepay.com",
        "key": (...),
      },
      "partner": {
        "node-id": "random@example.com",
      }
    },

    "note": "Let's have an account!"
  }
}
@]

An affirmative reply means the offer has been understood being held for consideration.  If the offer recipient accepts the offer, his node sends back an @@account-set@@ echoing the request ID and the full account data structure in the request, as well as a timestamp which is the official account creation time.

To indicate that the account has been created, the node receiving the @@account-set@@ responds with an affirmative reply.  If the reply is an error, the account is not created.

[[#identification-of-account-partner]]
'''Identification of Account Partner'''

Ripple has no universal mechanism for positively identifying the owner of another node.  The owner of a node receiving a new account request should confirm the identity of the owner of the requesting node before assigning it a non-zero credit limit.  Even if the node ID in the form ''node@host.com'' of the requesting node is familiar to the request recipient, one must ensure that the transport layer has verified positively by some means that the request actually comes from the correct host and that the host is trustworthy before relying solely on that piece of information.

The requesting node's owner may put secret, personal, or other information that could help the receiving node's owner identify them, such as a message signed with a personal signing key, into the @@note@@ field of the @@account-request@@.

[[#changing-account-data]]
'''Changing Account Data'''

To declare a change to one or more account data fields, a node sends a signed @@account-set@@ message to its account partner.  An affirmative reply by the other node indicates acceptance of those changes.  An error indicates rejection.

To request a change to one or more account data fields, a node sends an @@account-request@@ message.  An affirmative reply here only indicates that the request has been understood and is being held for approval. 

Once the request is approved, the request recipient sends an @@account-set@@ message echoing back the account fields and values and request ID from the @@account-request@@.  An affirmative reply to the @@account-set@@ completes the change.

[[#account-change-errors]]
'''Account Change Errors'''

The following errors allow nodes to negotiate between them what are permissible unilateral changes and what aren't in case of disagreement:

: ''Field change by account-request only'' : Contains path to field that node receiving an @@account-set@@ deems requires an @@account-request@@ to change in the manner requested.

: ''Unilateral declaration preferred'' : Node receiving an @@account-request@@ deems an @@account-set@@ preferable for the requested change.  (Equally valid is to simply accept the request immediately -- perhaps this error is unnecessary?)

[[#adding-new-fields]]
'''Adding New Fields'''

To add a new data field to an account, use @@account-set@@ or @@account-request@@ as appropriate.  If the other node does not understand the field, it will reply with an error, and the field may not be added.

[[#changing-keys]]
'''Changing Keys'''

An account message declaring or requesting a key change should be signed by the old key.  Subsequent signed messages must be signed by the new key.

[[#verifying-account-data]]
'''Verifying Account Data'''

To request a copy of an account partner's account data for verification, send an @@account-verify-request@@ message containing the account ID: 

Example:
[@
{
  "account-verify-request": {
    "account-id": "550e8400-e29b-41d4-a716-446655440000"
  }
}
@]

The immediate reply must contain the complete account data structure of the node receiving the @@account-verify-request@@ as well as a timestamp:

Example:
[@
{
  "account-verify": {
    "timestamp": "2006-11-07 02:11:28.401000",
    "account": {
      (...)
    }
  }
}
@]

Neither message nor reply must be signed.

[[#account-history]]
'''Account History'''

To request from an account partner a list of every signed message that has changed the value of an account field over a certain period, send an @@account-history-request@@:

Example:
[@
{
  "account-history-request": {
    "starting": "2006-01-01 00:00:00.000000",
    "ending": "2006-11-07 02:11:28.401000"
  }
}
@]

If the "starting" field is omitted, messages from beginning of the account should be included in the reply.  If the "ending" field is omitted, messages up to the present should be included.

The reply is as follows:

[@
{
  "account-history": [
    (a chronological order of signed messages sent and received over
    this account during the requested period that have changed a piece
    of shared account data, in the format they were originally sent or
    received, including signatures)
  ]
}
@]

This account history may be used as an audit to find the source of any data discrepancies between partners.  This same output may also be taken for each account by a node owner from her own node in order to backup account data or move a node to a different host.

[[#closing-an-account]]
'''Closing an Account'''

To close an account, either party may send an @@account-close@@ message containing the ID of the account to be closed:

Example:
[@
{
  "account-close": {
    "request-id": 14590,
    "account-id": "550e8400-e29b-41d4-a716-446655440000"
  }
}
@]

An affirmative reply indicates assent to close the account.  An error indicates refusal.


!!! Payments

To allow payments between two nodes that aren't neighbours, Ripple propagates value account-by-account along one or more paths of accounts in the network connecting payer and recipient.

The basic payment process consists of:

# Initializing payment between the payer and recipient nodes
# Preparing the paths to commit the transaction
# Committing the transaction

[[#requesting-payment]]
'''Requesting Payment'''

A node wishing to receive a payment from another node may initiate contact with the potential payer node by sending a @@payment-request@@ message to that node containing:

* unique ID for the payment
* amount
* units
* payment recipient's node's network address
* an explanatory note

[@
{
  "payment-request": {
    "payment-id": (string),
    "amount": (decimal),
    "unit": (URI),
    "recipient-node-id": (Ripple ID),
    "note": (string)
  }
}
@]

The @@payment-request@@ may be followed by an @@payment-init@@ message from the potential payer, or ignored.

The @@payment-request@@ message may be authorized by signing it with a certain key, contained in the node owner's smart card, for example, for point-of-sale scenarios where the buyer is unable to communicate directly with his or her node.  (Ideally, the smart card would display the payment amount and units to the buyer for approval, otherwise he or she must trust that the seller's terminal displays the same amount as it is asking the smart card to authorize in the @@payment-request@@ message.)

[[#initializing-payment]]
'''Initializing Payment'''

The payer node contacts recipient node and communicates the following in a @@payment-init@@ message:

* unique ID for the payment
* amount to be paid to recipient
* units of payment
* some explanatory text to the recipient

[@
{
  "payment-init": {
    "payment-id": (string),
    "amount": (decimal),
    "units": (URI),
    "note": (string)
  }
}
@]

The recipient may accept the @@payment-init@@ with an affirmative reply containing a @@payment-accept@@ message with the following data:

* payment ID
* amount to be paid to recipient
* units of payment
* payer's explanatory text echoed back
* recipient's authentication key for payment (used to sign receipts)
* public-key certificate establishing recipient's identity to the payer

[@
{
  "payment-accept": {
    "payment-id": (string),
    "amount": (decimal),
    "units": (URI),
    "note": (string),
    "recipient-receipt-key": (public key data structure),
    "recipient-certificate": (certificate data structure)
  }
}
@]

This must be signed by the recipient's identifying certificate key, whose certificate identifies the recipient in a way acceptable to the payer, such as being issued (i.e., signed) by an authority recognized by the payer.  This message serves as evidence that the recipient participated in the transaction.  Thus the signature of the recipient's receipt key on the payment receipts can be irrevocably connected the recipient, proving that the payment was indeed received.  The explanatory text can contain text linking the payment to a real-world exchange of goods or services, such as "Payment for auction item #12345".

The recipient may reject the @@payment-init@@ with an error code.

[[#making-promises]]
'''Making Promises (Commit-Request)'''

To prepare the payment paths, the payer sends a @@promise@@ message to the first node on each path, representing its commitment to redeem a valid receipt that can be authenticated with the promise's authentication key up to the amount of credit indicated on the receipt, if presented before the stated deadline.

* payment ID
* search ID
* path ID
* amount to be held for payment, in path units
* ID of account to be made part of path by this promise being passed
* amount to be held for payment, in account units
* a routing onion (optional)
* a time limit to reach the recipient, in connection time
* promise penalty deadline, in connection time
* daily penalty rate if receipt or path-cancel not received before the penalty deadline
* promise final deadline, in connection time, after which promise expires
* the payer's receipt authentication key for this payment path
* the recipient's receipt authentication key for this payment path
* a timestamp to indicate the time the promise came into effect, in connection time

[@
{
  "promise": {
    "payment-id": (string),
    "search-id": (integer),
    "path-id": (string),
    "path-amount": (decimal),
    "account-id": (string),
    "amount": (decimal),
    "onion": (routing onion data structure),
    "ttl": (date/time string),
    "penalty-deadline": (date/time string),
    "penalty-rate": (decimal),
    "deadline": (date/time string),
    "payer-receipt-key": (public key data structure),
    "recipient-receipt-key": (public key data structure),
    "timestamp": (date/time string)
  }
@]

Since a promise must be fulfilled if a valid @@receipt@@ is presented, it must effectively hold the required amount on the designated account in such a way that no other transaction may invalidate the payment.

Each node that receives a promise message updates its fields and passes it on to the next node in the path, as determined by data gleaned from the routing onion and/or by extension fields that inform a routing system defined in a protocol extension.  At each step, the promise message is signed to the next node by the passing node's authentication key.  This serves to establish the integrity and non-repudiability of the promise.

The @@search-id@@ allows the payer to send of multiple sets of promises down different potential paths without interfering with each other.  An intermediary may use the same credit hold on an account to cover promises with the same @@payment-id@@ but different @@search-ids@@.  In the end, the payer may only issue receipts for a single @@search-id@@, and the rest must be released.  By issuing multiple sets of promises, the payer increases the chance of more quickly finding a useable set of paths, and, if multiple useable sets are found, the payer may choose the cheapest among them.

The @@path-amount@@ is invented by the payer and given in arbitrary units (''path units'') particular to each path.  This figure gives each intermediary a reference against which to know the value of the @@receipt@@ message that commits the transaction, which will contain a @@path-amount@@ less than or equal to the @@promise@@ @@path-amount@@. 

The @@ttl@@ (''time-to-live'') field allows the payer to specify a deadline for the @@promise@@ to reach the recipient.  If it should fail to reach the recipient by that time, the latest receiver of the @@promise@@ should release the sender from its promise, and so on back to the payer (see [[Releasing Promises -> #releasing-promises]] below).  This field allows the payer to reasonably limit the amount of time it wishes to wait to see whether the path is viable.

The @@penalty-deadline@@ is the time after which the promising node may begin charging a penalty to its partner for having to hold credit it could be using for payment.  The penalty is charged continuously at the daily rate specified.  Intermediaries should always set a shorter deadline and higher penalty rate on promises out than they have received on promises in, to ensure that they are compensated for overdue @@receipts@@.  This provides incentive for the recipient to ensure quick completion or cancellation of each promise path, without requiring hard-and-fast deadlines to come into play so soon that minor delays relaying the receipt back along the path spawn major disputes.

[[#finalizing-payment]]
'''Finalizing the Payment'''

If the recipient receives promises in a single @@search-id@@ set totalling (in @@account-amounts, after conversion by the recipient) an amount greater than or equal to the payment amount designated in the @@payment-init@@ message, it sends the payer a @@promise-bundle@@ message containing:

* payment ID
* search ID
* recipient's deadline for accepting the receipts for these paths, in connection time
* for each promise received:
  * path ID
  * final amount of promise in payment units as computed by recipient

[@
{
  "promise-bundle": {
    "payment-id": (string),
    "search-id": (integer),
    "deadline": (date/time string),
    "promises": [
      {
        "path-id": (string),
        "amount": (decimal)
      }, {
        "path-id": (string),
        "amount": (decimal)
      }, (etc.)
    ]
  }
}
@]

The recipient's receipt deadline to the payer should be well before the penalty deadline on any promise received.

The recipient can cancel the transaction at any time by sending the payer a @@payment-cancel@@ and releasing its neighbours from their promises with a @@promise-release@@ (see [[Releasing Promises -> #releasing-promises]]).  The payer can cancel the transaction by sending the recipient a @@payment-cancel@@, informing it that it can release its neighbours from their promises.  Released promises should be propagated back down each payment path to free up those funds for other payments.

When the payer receives satisfactory @@promise-bundle@@, it generates @@receipt@@ messages corresponding to the @@promise@@s in it – one receipt per @@promise@@/path – and totalling the payment amount, authenticates them individually with each path's @@payer-receipt-key@@, and sends them each to the recipient:

* payment ID
* search ID
* path ID
* amount for this path, in path units

[@
{
  "receipt": {
    "payment-id": (string),
    "search-id": (integer),
    "path-id": (string),
    "path-amount": (decimal)
  }
@]

The collection of receipts signed by the payer represents the value of the payment, and once they are given to the recipient, the recipient is considered to have been paid.  If any of the receipts is invalid (to be rigorously defined), the amount of that receipt is not considered to have been paid until a valid receipt is issued.  The recipient must reply with an error code when receiving an invalid receipt.

[[PaymentProtocolWorkPage]]