gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[taler-docs] branch master updated: restructure merchant API documentati


From: gnunet
Subject: [taler-docs] branch master updated: restructure merchant API documentation (#6492)
Date: Sat, 31 Oct 2020 16:09:09 +0100

This is an automated email from the git hooks/post-receive script.

grothoff pushed a commit to branch master
in repository docs.

The following commit(s) were added to refs/heads/master by this push:
     new f82d509  restructure merchant API documentation (#6492)
f82d509 is described below

commit f82d5092cdc8fa3a123404f680b43a937cc6ef11
Author: Christian Grothoff <christian@grothoff.org>
AuthorDate: Sat Oct 31 16:08:52 2020 +0100

    restructure merchant API documentation (#6492)
---
 core/api-common.rst       |    9 +
 core/api-exchange.rst     |   28 +-
 core/api-merchant.rst     | 2374 ++++++++++++++++++++++++---------------------
 taler-merchant-manual.rst |    6 +-
 4 files changed, 1291 insertions(+), 1126 deletions(-)

diff --git a/core/api-common.rst b/core/api-common.rst
index 1364ae5..12f4a36 100644
--- a/core/api-common.rst
+++ b/core/api-common.rst
@@ -335,6 +335,15 @@ Blinded coin
   // Blinded coin's `public EdDSA key <eddsa-coin-pub>`, `base32` encoded
   type CoinEnvelope = string;
 
+.. ts:def:: DenominationBlindingKeyP
+
+   // Secret for blinding/unblinding.
+   // An RSA blinding secret, which is basically
+   // a 256-bit nonce, converted to Crockford `Base32`.
+   type DenominationBlindingKeyP = string;
+
+
+  
 .. _signature:
 
 Signatures
diff --git a/core/api-exchange.rst b/core/api-exchange.rst
index bc6a98d..8b5c43c 100644
--- a/core/api-exchange.rst
+++ b/core/api-exchange.rst
@@ -1435,21 +1435,21 @@ Refunds
       exchange_pub: EddsaPublicKey;
    }
 
-   .. ts:def:: RefundFailure
+  .. ts:def:: RefundFailure
 
-   interface RefundFailure {
+    interface RefundFailure {
 
-     // Numeric error code unique to the condition, which can be either
-     // related to the deposit value being insufficient for the requested
-     // refund(s), or the requested refund conflicting due to refund
-     // transaction number re-use (with different amounts).
-     code: number;
+      // Numeric error code unique to the condition, which can be either
+      // related to the deposit value being insufficient for the requested
+      // refund(s), or the requested refund conflicting due to refund
+      // transaction number re-use (with different amounts).
+      code: number;
 
-     // Human-readable description of the error message
-     hint: string;
+      // Human-readable description of the error message
+      hint: string;
 
-     // Information about the conflicting refund request(s).
-     // This will not be the full history of the coin, but only
-     // the relevant subset of the transactions.
-     history: CoinSpendHistoryItem[];
-   }
+      // Information about the conflicting refund request(s).
+      // This will not be the full history of the coin, but only
+      // the relevant subset of the transactions.
+      history: CoinSpendHistoryItem[];
+    }
diff --git a/core/api-merchant.rst b/core/api-merchant.rst
index 809bcbf..53b6424 100644
--- a/core/api-merchant.rst
+++ b/core/api-merchant.rst
@@ -35,9 +35,12 @@ used.
 .. contents:: Table of Contents
 
 
--------------------------
-Getting the configuration
--------------------------
+-----------------
+Configuration API
+-----------------
+
+The configuration API exposes basic information about a merchant backend,
+such as the implemented version of the protocol and the currency used.
 
 .. http:get:: /config
 
@@ -63,1177 +66,1530 @@ Getting the configuration
       currency: string;
 
     }
+    
 
+----------
+Wallet API
+----------
 
---------------------------
-Dynamic Merchant Instances
---------------------------
+This section describes (public) endpoints that wallets must be able
+to interact with directly (without HTTP-based authentication). These
+endpoints are used to process payments (claiming an order, paying
+for the order, checking payment/refund status and aborting payments),
+process refunds (check refund status, obtain refund), and to pickup
+tips.
 
-.. _instances:
-.. http:get:: /private/instances
 
-  This is used to return the list of all the merchant instances
+Claiming an order
+-----------------
 
-  **Response:**
+The first step of processing any Taler payment consists of the
+(authorized) wallet claiming the order for itself. In this process,
+the wallet provides a wallet-generated nonce that is added
+into the contract terms.  This step prevents two different
+wallets from paying for the same contract, which would be bad
+especially if the merchant only has finite stocks.
 
-  :status 200 OK:
-    The backend has successfully returned the list of instances stored. Returns
-    a `InstancesResponse`.
+A claim token can be used to ensure that the wallet claiming an
+order is actually authorized to do so. This is useful in cases
+where order IDs are predictable and malicious actors may try to
+claim orders (say in a case where stocks are limited).
 
-  .. ts:def:: InstancesResponse
 
-    interface InstancesResponse {
-      // List of instances that are present in the backend (see `Instance`)
-      instances: Instance[];
-    }
+.. http:post:: /orders/$ORDER_ID/claim
 
-  The `Instance` object describes the instance registered with the backend.
-  It does not include the full details, only those that usually concern the 
frontend.
-  It has the following structure:
+  Wallet claims ownership (via nonce) over an order.  By claiming
+  an order, the wallet obtains the full contract terms, and thereby
+  implicitly also the hash of the contract terms it needs for the
+  other ``/public/`` APIs to authenticate itself as the wallet that
+  is indeed eligible to inspect this particular order's status.
 
-  .. ts:def:: Instance
+  **Request:**
 
-    interface Instance {
-      // Merchant name corresponding to this instance.
-      name: string;
+  The request must be a `ClaimRequest`
 
-      // Merchant instance this response is about ($INSTANCE)
-      id: string;
+  .. ts:def:: ClaimRequest
 
-      // Public key of the merchant/instance, in Crockford Base32 encoding.
-      merchant_pub: EddsaPublicKey;
+    interface ClaimRequest {
+      // Nonce to identify the wallet that claimed the order.
+      nonce: string;
 
-      // List of the payment targets supported by this instance. Clients can
-      // specify the desired payment target in /order requests.  Note that
-      // front-ends do not have to support wallets selecting payment targets.
-      payment_targets: string[];
+      // Token that authorizes the wallet to claim the order.
+      // *Optional* as the merchant may not have required it
+      // (``create_token`` set to ``false`` in `PostOrderRequest`).
+      token?: ClaimToken;
+    }
 
-   }
+  **Response:**
+
+  :status 200 OK:
+    The client has successfully claimed the order.
+    The response contains the :ref:`contract terms <contract-terms>`.
+  :status 404 Not found:
+    The backend is unaware of the instance or order.
+  :status 409 Conflict:
+    The someone else claimed the same order ID with different nonce before.
 
+  .. ts:def:: ClaimResponse
 
-.. http:post:: /private/instances
+    interface ClaimResponse {
+      // Contract terms of the claimed order
+      contract_terms: ContractTerms;
 
-  This request will be used to create a new merchant instance in the backend.
+      // Signature by the merchant over the contract terms.
+      sig: EddsaSignature;
+    }
+    
+Making the payment
+------------------
+
+.. http:post:: /orders/$ORDER_ID/pay
+
+  Pay for an order by giving a deposit permission for coins.  Typically used by
+  the customer's wallet.  Note that this request does not include the
+  usual ``h_contract`` argument to authenticate the wallet, as the hash of
+  the contract is implied by the signatures of the coins.  Furthermore, this
+  API doesn't really return useful information about the order.
 
   **Request:**
 
-  The request must be a `InstanceConfigurationMessage`.
+  The request must be a `pay request <PayRequest>`.
 
   **Response:**
 
-  :status 204 No content:
-    The backend has successfully created the instance.
+  :status 200 OK:
+    The exchange accepted all of the coins.
+    The body is a `payment response <PaymentResponse>`.
+    The ``frontend`` should now fulfill the contract.
+    Note that it is possible that refunds have been granted.
+  :status 400 Bad request:
+    Either the client request is malformed or some specific processing error
+    happened that may be the fault of the client as detailed in the JSON body
+    of the response.
+  :http:statuscode:`402 Payment required`:
+    There used to be a sufficient payment, but due to refunds the amount 
effectively
+    paid is no longer sufficient. (If the amount is generally insufficient, we
+    return "406 Not Acceptable", only if this is because of refunds we return 
402.)
+  :status 403 Forbidden:
+    One of the coin signatures was not valid.
+  :status 404 Not found:
+    The merchant backend could not find the order or the instance and thus 
cannot process the payment.
+  :status 406 Not Acceptable:
+    The payment is insufficient (sum is below the required total amount).
+  :status 408 Request Timeout:
+    The backend took too long to process the request. Likely the merchant's 
connection
+    to the exchange timed out. Try again.
   :status 409 Conflict:
-    This instance already exists, but with other configuration options.
-    Use "PATCH" to update an instance configuration.
+    The exchange rejected the payment because a coin was already spent before.
+    The response will include the ``coin_pub`` for which the payment failed,
+    in addition to the response from the exchange to the ``/deposit`` request.
+  :status 410 Gone:
+    The offer has expired and is no longer available.
+  :status 412 Precondition Failed:
+    The given exchange is not acceptable for this merchant, as it is not in the
+    list of accepted exchanges and not audited by an approved auditor.
+  :status 424 Failed Dependency:
+    The merchant's interaction with the exchange failed in some way.
+    The client might want to try later again.
+    This includes failures like the denomination key of a coin not being
+    known to the exchange as far as the merchant can tell.
 
-  .. ts:def:: InstanceConfigurationMessage
+  The backend will return verbatim the error codes received from the exchange's
+  :ref:`deposit <deposit>` API.  If the wallet made a mistake, like by
+  double-spending for example, the frontend should pass the reply verbatim to
+  the browser/wallet.  If the payment was successful, the frontend MAY use
+  this to trigger some business logic.
 
-    interface InstanceConfigurationMessage {
-      // The URI where the wallet will send coins.  A merchant may have
-      // multiple accounts, thus this is an array.  Note that by
-      // removing URIs from this list the respective account is set to
-      // inactive and thus unavailable for new contracts, but preserved
-      // in the database as existing offers and contracts may still refer
-      // to it.
-      payto_uris: string[];
+  .. ts:def:: PaymentResponse
 
-      // Name of the merchant instance to create (will become $INSTANCE).
-      id: string;
+    interface PaymentResponse {
+      // Signature on ``TALER_PaymentResponsePS`` with the public
+      // key of the merchant instance.
+      sig: EddsaSignature;
 
-      // Merchant name corresponding to this instance.
-      name: string;
+    }
 
-      // The merchant's physical address (to be put into contracts).
-      address: Location;
+  .. ts:def:: PayRequest
 
-      // The jurisdiction under which the merchant conducts its business
-      // (to be put into contracts).
-      jurisdiction: Location;
+    interface PayRequest {
+      // The coins used to make the payment.
+      coins: CoinPaySig[];
 
-      // Maximum wire fee this instance is willing to pay.
-      // Can be overridden by the frontend on a per-order basis.
-      default_max_wire_fee: Amount;
+      // The session for which the payment is made (or replayed).
+      // Only set for session-based payments.
+      session_id?: string;
 
-      // Default factor for wire fee amortization calculations.
-      // Can be overridden by the frontend on a per-order basis.
-      default_wire_fee_amortization: Integer;
+    }
 
-      // Maximum deposit fee (sum over all coins) this instance is willing to 
pay.
-      // Can be overridden by the frontend on a per-order basis.
-      default_max_deposit_fee: Amount;
+  .. ts:def:: CoinPaySig
 
-      //  If the frontend does NOT specify an execution date, how long should
-      // we tell the exchange to wait to aggregate transactions before
-      // executing the wire transfer?  This delay is added to the current
-      // time when we generate the advisory execution time for the exchange.
-      default_wire_transfer_delay: RelativeTime;
+    export interface CoinPaySig {
+      // Signature by the coin.
+      coin_sig: EddsaSignature;
 
-      // If the frontend does NOT specify a payment deadline, how long should
-      // offers we make be valid by default?
-      default_pay_delay: RelativeTime;
+      // Public key of the coin being spend.
+      coin_pub: EddsaPublicKey;
+
+      // Signature made by the denomination public key.
+      ub_sig: RsaSignature;
+
+      // The hash of the denomination public key associated with this coin.
+      h_denom: HashCode;
+
+      // The amount that is subtracted from this coin with this payment.
+      contribution: Amount;
 
+      // URL of the exchange this coin was withdrawn from.
+      exchange_url: string;
     }
 
+Querying payment status
+-----------------------
 
-.. http:patch:: /private/instances/$INSTANCE
+.. http:get:: /orders/$ORDER_ID
 
-  Update the configuration of a merchant instance.
+  Query the payment status of an order. This endpoint is for the wallet.
+  When the wallet goes to this URL and it is unpaid,
+  they will be prompted for payment.
+  This endpoint typically also supports requests with the "Accept" header
+  requesting "text/html".  In this case, an HTML response suitable for
+  triggering the interaction with the wallet is returned, with ``timeout_ms``
+  ignored (treated as zero). If the backend installation does not include the
+  required HTML templates, a 406 status code is returned.
 
-  **Request**
+  In the case that the request was made with a claim token (even the wrong one)
+  and the order was claimed and paid, the server will redirect the client to
+  the fulfillment URL.  This redirection will happen with a 302 status code
+  if the "Accept" header specified "text/html", and with a 202 status code
+  otherwise.
 
-  The request must be a `InstanceReconfigurationMessage`.
-  Removing an existing payto_uri deactivates
-  the account (it will no longer be used for future contracts).
+  **Request:**
+
+  :query h_contract=HASH: hash of the order's contract terms (this is used to 
authenticate the wallet/customer in case $ORDER_ID is guessable). Required once 
an order was claimed.
+  :query token=TOKEN: *Optional*. Authorizes the request via the claim token 
that was returned  in the `PostOrderResponse`.  Used with unclaimed orders 
only. Whether token authorization is required is determined by the merchant 
when the frontend creates the order.
+  :query session_id=STRING: *Optional*. Session ID that the payment must be 
bound to.  If not specified, the payment is not session-bound.
+  :query timeout_ms=NUMBER: *Optional.*  If specified, the merchant backend 
will
+    wait up to ``timeout_ms`` milliseconds for completion of the payment before
+    sending the HTTP response.  A client must never rely on this behavior, as 
the
+    merchant backend may return a response immediately.
+  :query refund=AMOUNT: *Optional*. Indicates that we are polling for a refund 
above the given AMOUNT. Only useful in combination with timeout.
+  :query await_refund_obtained=BOOLEAN: *Optional*. If set to "yes", poll for 
the order's pending refunds to be picked up.
 
   **Response:**
 
-  :status 204 No content:
-    The backend has successfully created the instance.
+  :status 200 OK:
+    The response is a `StatusPaidResponse`.
+  :status 202 Accepted:
+    The response is a `StatusGotoResponse`. Only returned if the content type 
requested was not HTML.
+  :status 302 Found:
+    The client should go to the indicated location. Only returned if the 
content type requested was HTML.
+  :status 402 PaymentRequired:
+    The response is a `StatusUnpaidResponse`.
+  :status 403 Forbidden:
+    The ``h_contract`` (or the ``token`` for unclaimed orders) does not match 
the order
+    and we have no fulfillment URL in the contract.
+  :status 410 Gone:
+    The response is a `StatusGoneResponse`.
   :status 404 Not found:
-    This instance is unknown and thus cannot be reconfigured.
+    The merchant backend is unaware of the order.
+  :status 406 Not Acceptable:
+    The merchant backend could not load the template required to generate a 
reply in the desired format. (Likely HTML templates were not properly 
installed.)
 
-  .. ts:def:: InstanceReconfigurationMessage
+  .. ts:def:: StatusPaidResponse
 
-    interface InstanceReconfigurationMessage {
-      // The URI where the wallet will send coins.  A merchant may have
-      // multiple accounts, thus this is an array.  Note that by
-      // removing URIs from this list
-      payto_uris: string[];
+    interface StatusPaid {
+      // Was the payment refunded (even partially, via refund or abort)?
+      refunded: boolean;
 
-      // Merchant name corresponding to this instance.
-      name: string;
+      // Is any amount of the refund still waiting to be picked up (even 
partially)
+      refund_pending: boolean;
 
-      // The merchant's physical address (to be put into contracts).
-      address: Location;
+      // Amount that was refunded in total.
+      refund_amount: Amount;
+    }
 
-      // The jurisdiction under which the merchant conducts its business
-      // (to be put into contracts).
-      jurisdiction: Location;
-
-      // Maximum wire fee this instance is willing to pay.
-      // Can be overridden by the frontend on a per-order basis.
-      default_max_wire_fee: Amount;
+  .. ts:def:: StatusGotoResponse
 
-      // Default factor for wire fee amortization calculations.
-      // Can be overridden by the frontend on a per-order basis.
-      default_wire_fee_amortization: Integer;
+    interface StatusGotoResponse {
+      // The client should go to the fulfillment URL, it may be ready or
+      // might have some other interesting status.
+      fulfillment_url: string;
+    }
 
-      // Maximum deposit fee (sum over all coins) this instance is willing to 
pay.
-      // Can be overridden by the frontend on a per-order basis.
-      default_max_deposit_fee: Amount;
+  .. ts:def:: StatusUnpaidResponse
 
-      //  If the frontend does NOT specify an execution date, how long should
-      // we tell the exchange to wait to aggregate transactions before
-      // executing the wire transfer?  This delay is added to the current
-      // time when we generate the advisory execution time for the exchange.
-      default_wire_transfer_delay: RelativeTime;
+    interface StatusUnpaidResponse {
+      // URI that the wallet must process to complete the payment.
+      taler_pay_uri: string;
 
-      // If the frontend does NOT specify a payment deadline, how long should
-      // offers we make be valid by default?
-      default_pay_delay: RelativeTime;
+      // Status URL, can be used as a redirect target for the browser
+      // to show the order QR code / trigger the wallet.
+      fulfillment_url?: string;
 
+      // Alternative order ID which was paid for already in the same session.
+      // Only given if the same product was purchased before in the same 
session.
+      already_paid_order_id?: string;
     }
 
+  .. ts:def:: StatusGoneResponse
 
-.. http:get:: /private/instances/$INSTANCE
-
-  This is used to query a specific merchant instance.
-
-  **Response:**
+    // The client tried to access the order via the claim
+    // token (and not a valid h_contract), but the order can't be claimed
+    // anymore, as it is already paid.
+    interface StatusGoneResponse {
+      // Fulfillment URL for the order.
+      fulfillment_url: string;
+    }
 
-  :status 200 OK:
-    The backend has successfully returned the list of instances stored. Returns
-    a `QueryInstancesResponse`.
+    
+Demonstrating payment
+---------------------
 
-  .. ts:def:: QueryInstancesResponse
+In case a wallet has already paid for an order, this is a fast way of proving
+to the merchant that the order was already paid. The alternative would be to
+replay the original payment, but simply providing the merchant's signature
+saves bandwidth and computation time.
 
-    interface QueryInstancesResponse {
-      // The URI where the wallet will send coins.  A merchant may have
-      // multiple accounts, thus this is an array.
-      accounts: MerchantAccount[];
+Demonstrating payment is useful in case a digital good was made available
+only to clients with a particular session ID: if that session ID expired or
+if the user is using a different client, demonstrating payment will allow
+the user to regain access to the digital good without having to pay for it
+again.
 
-      // Merchant name corresponding to this instance.
-      name: string;
+.. http:post:: /orders/$ORDER_ID/paid
 
-      // Public key of the merchant/instance, in Crockford Base32 encoding.
-      merchant_pub: EddsaPublicKey;
+  Prove that the client previously paid for an order by providing
+  the merchant's signature from the `payment response <PaymentResponse>`.
+  Typically used by the customer's wallet if it receives a request for
+  payment for an order that it already paid. This is more compact then
+  re-transmitting the full payment details.
+  Note that this request does include the
+  usual ``h_contract`` argument to authenticate the wallet and
+  to allow the merchant to verify the signature before checking
+  with its own database.
 
-      // The merchant's physical address (to be put into contracts).
-      address: Location;
+  **Request:**
 
-      // The jurisdiction under which the merchant conducts its business
-      // (to be put into contracts).
-      jurisdiction: Location;
+  The request must be a `paid request <PaidRequest>`.
 
-      // Maximum wire fee this instance is willing to pay.
-      // Can be overridden by the frontend on a per-order basis.
-      default_max_wire_fee: Amount;
+  **Response:**
 
-      // Default factor for wire fee amortization calculations.
-      // Can be overridden by the frontend on a per-order basis.
-      default_wire_fee_amortization: Integer;
+  :status 204 No content:
+    The merchant accepted the signature.
+    The ``frontend`` should now fulfill the contract.
+    Note that it is possible that refunds have been granted.
+  :status 400 Bad request:
+    Either the client request is malformed or some specific processing error
+    happened that may be the fault of the client as detailed in the JSON body
+    of the response.
+  :status 403 Forbidden:
+    The signature was not valid.
+  :status 404 Not found:
+    The merchant backend could not find the order or the instance
+    and thus cannot process the request.
+  :status 409 Conflict:
+    The provided contract hash does not match this order.
 
-      // Maximum deposit fee (sum over all coins) this instance is willing to 
pay.
-      // Can be overridden by the frontend on a per-order basis.
-      default_max_deposit_fee: Amount;
+  .. ts:def:: PaidRequest
 
-      //  If the frontend does NOT specify an execution date, how long should
-      // we tell the exchange to wait to aggregate transactions before
-      // executing the wire transfer?  This delay is added to the current
-      // time when we generate the advisory execution time for the exchange.
-      default_wire_transfer_delay: RelativeTime;
+    interface PaidRequest {
+      // Signature on ``TALER_PaymentResponsePS`` with the public
+      // key of the merchant instance.
+      sig: EddsaSignature;
 
-      // If the frontend does NOT specify a payment deadline, how long should
-      // offers we make be valid by default?
-      default_pay_deadline: RelativeTime;
+      // hash of the order's contract terms (this is used to authenticate the
+      // wallet/customer and to enable signature verification without
+      // database access).
+      h_contract: HashCode;
 
+      // Session id for which the payment is proven.
+      session_id: string;
     }
 
-  .. ts:def:: MerchantAccount
-
-    interface MerchantAccount {
-
-      // payto:// URI of the account.
-      payto_uri: string;
-
-      // Hash over the wire details (including over the salt)
-      h_wire: HashCode;
-
-      // salt used to compute h_wire
-      salt: HashCode;
-
-      // true if this account is active,
-      // false if it is historic.
-      active: boolean;
-    }
+    
+Aborting incomplete payments
+----------------------------
 
+In rare cases (such as a wallet restoring from an outdated backup) it is 
possible
+that a wallet fails to complete a payment because it runs out of e-cash in the
+middle of the process. The abort API allows the wallet to abort the payment for
+such an incomplete payment and to regain control over the coins that were spent
+so far. Aborts are not permitted for payments that completed.  In contrast to
+refunds, aborts do not require approval by the merchant because aborts always
+are for incomplete payments for an order and never for established contracts.
 
 
-.. http:delete:: /private/instances/$INSTANCE
+.. _order-abort:
+.. http:post:: /orders/$ORDER_ID/abort
 
-  This request will be used to delete (permanently disable)
-  or purge merchant instance in the backend. Purging will
-  delete all offers and payments associated with the instance,
-  while disabling (the default) only deletes the private key
-  and makes the instance unusable for new orders or payments.
+  Abort paying for an order and obtain a refund for coins that
+  were already deposited as part of a failed payment.
 
   **Request:**
 
-  :query purge: *Optional*. If set to YES, the instance will be fully
-      deleted. Otherwise only the private key would be deleted.
+  The request must be an `abort request <AbortRequest>`.  We force the wallet
+  to specify the affected coins as it may only request for a subset of the 
coins
+  (i.e. because the wallet knows that some were double-spent causing the 
failure).
+  Also we need to know the coins because there may be two wallets "competing" 
over
+  the same order and one wants to abort while the other still proceeds with the
+  payment. Here we need to again know which subset of the deposits to abort.
 
-  **Response**
+  **Response:**
 
-  :status 204 No content:
-    The backend has successfully removed the instance.  The body is empty.
+  :status 200 OK:
+    The merchant accepted the request, and passed it on to the exchange. The 
body is a
+    a `merchant refund response <MerchantRefundResponse>`. Note that the 
exchange
+    MAY still have encountered errors in processing. Those will then be part of
+    the body. Wallets MUST carefully consider errors for each of the coins as
+    returned by the exchange.
+  :status 400 Bad request:
+    Either the client request is malformed or some specific processing error
+    happened that may be the fault of the client as detailed in the JSON body
+    of the response.
+  :status 403 Forbidden:
+    The ``h_contract`` does not match the $ORDER_ID.
   :status 404 Not found:
-    The instance is unknown to the backend.
-  :status 409 Conflict:
-    The instance cannot be deleted because it has pending offers, or
-    the instance cannot be purged because it has successfully processed
-    payments that have not passed the TAX_RECORD_EXPIRATION time.
-    The latter case only applies if ``purge`` was set.
-
-
---------------------
-Inventory management
---------------------
+    The merchant backend could not find the order or the instance
+    and thus cannot process the abort request.
+  :status 408 Request Timeout:
+    The merchant backend took too long getting a response from the exchange.
+    The wallet SHOULD retry soon.
+  :status 412 Precondition Failed:
+    Aborting the payment is not allowed, as the original payment did succeed.
+    It is possible that a different wallet succeeded with the payment. This
+    wallet should thus try to refresh all of the coins involved in the payment.
+  :status 424 Failed Dependency:
+    The merchant's interaction with the exchange failed in some way.
+    The error from the exchange is included.
 
-.. _inventory:
+  The backend will return an `abort response <AbortResponse>`, which includes
+  verbatim the error codes received from the exchange's
+  :ref:`refund <exchange_refund>` API.  The frontend should pass the replies 
verbatim to
+  the browser/wallet.
 
-Inventory management is an *optional* backend feature that can be used to
-manage limited stocks of products and to auto-complete product descriptions in
-contracts (such that the frontends have to do less work).  You can use the
-Taler merchant backend to process payments *without* using its inventory
-management.
+  .. ts:def:: AbortRequest
 
+    interface AbortRequest {
 
-.. http:get:: /private/products
+      // hash of the order's contract terms (this is used to authenticate the
+      // wallet/customer in case $ORDER_ID is guessable).
+      h_contract: HashCode;
 
-  This is used to return the list of all items in the inventory.
+      // List of coins the wallet would like to see refunds for.
+      // (Should be limited to the coins for which the original
+      // payment succeeded, as far as the wallet knows.)
+      coins: AbortingCoin[];
+    }
 
-  **Response:**
+  .. ts:def:: AbortingCoin
 
-  :status 200 OK:
-    The backend has successfully returned the inventory. Returns
-    a `InventorySummaryResponse`.
+    interface AbortingCoin {
+      // Public key of a coin for which the wallet is requesting an 
abort-related refund.
+      coin_pub: EddsaPublicKey;
 
-  .. ts:def:: InventorySummaryResponse
+      // The amount to be refunded (matches the original contribution)
+      contribution: Amount;
 
-    interface InventorySummaryResponse {
-      // List of products that are present in the inventory
-      products: InventoryEntry[];
+      // URL of the exchange this coin was withdrawn from.
+      exchange_url: string;
     }
 
-  The `InventoryEntry` object describes an item in the inventory. It has the 
following structure:
 
-  .. ts:def:: InventoryEntry
+  .. ts:def:: AbortResponse
 
-    interface InventoryEntry {
-      // Product identifier, as found in the product.
-      product_id: string;
+    interface AbortResponse {
 
+      // List of refund responses about the coins that the wallet
+      // requested an abort for.  In the same order as the 'coins'
+      // from the original request.
+      // The rtransaction_id is implied to be 0.
+      refunds: MerchantAbortPayRefundStatus[];
     }
 
+  .. ts:def:: MerchantAbortPayRefundStatus
 
-.. http:get:: /private/products/$PRODUCT_ID
-
-  This is used to obtain detailed information about a product in the inventory.
+    type MerchantAbortPayRefundStatus =
+      | MerchantAbortPayRefundSuccessStatus
+      | MerchantAbortPayRefundFailureStatus;
 
-  **Response:**
+  .. ts:def:: MerchantAbortPayRefundFailureStatus
 
-  :status 200 OK:
-    The backend has successfully returned the inventory. Returns
-    a `ProductDetail`.
-
-  .. ts:def:: ProductDetail
-
-    interface ProductDetail {
-
-      // Human-readable product description.
-      description: string;
+    // Details about why a refund failed.
+    interface MerchantAbortPayRefundFailureStatus {
+      // Used as tag for the sum type RefundStatus sum type.
+      type: "failure"
 
-      // Map from IETF BCP 47 language tags to localized descriptions
-      description_i18n: { [lang_tag: string]: string };
+      // HTTP status of the exchange request, must NOT be 200.
+      exchange_status: Integer;
 
-      // unit in which the product is measured (liters, kilograms, packages, 
etc.)
-      unit: string;
+      // Taler error code from the exchange reply, if available.
+      exchange_code?: Integer;
 
-      // The price for one ``unit`` of the product. Zero is used
-      // to imply that this product is not sold separately, or
-      // that the price is not fixed, and must be supplied by the
-      // front-end.  If non-zero, this price MUST include applicable
-      // taxes.
-      price: Amount;
+      // If available, HTTP reply from the exchange.
+      exchange_reply?: Object;
+    }
 
-      // An optional base64-encoded product image
-      image: ImageDataUrl;
+  .. ts:def:: MerchantAbortPayRefundSuccessStatus
 
-      // a list of taxes paid by the merchant for one unit of this product
-      taxes: Tax[];
+    // Additional details needed to verify the refund confirmation signature
+    // (``h_contract_terms`` and ``merchant_pub``) are already known
+    // to the wallet and thus not included.
+    interface MerchantAbortPayRefundSuccessStatus {
+      // Used as tag for the sum type MerchantCoinRefundStatus sum type.
+      type: "success"
 
-      // Number of units of the product in stock in sum in total,
-      // including all existing sales ever. Given in product-specific
-      // units.
-      // A value of -1 indicates "infinite" (i.e. for "electronic" books).
-      total_stock: Integer;
+      // HTTP status of the exchange request, 200 (integer) required for 
refund confirmations.
+      exchange_status: 200;
 
-      // Number of units of the product that have already been sold.
-      total_sold: Integer;
+      // the EdDSA :ref:`signature` (binary-only) with purpose
+      // `TALER_SIGNATURE_EXCHANGE_CONFIRM_REFUND` using a current signing key 
of the
+      // exchange affirming the successful refund
+      exchange_sig: EddsaSignature;
 
-      // Number of units of the product that were lost (spoiled, stolen, etc.)
-      total_lost: Integer;
+      // public EdDSA key of the exchange that was used to generate the 
signature.
+      // Should match one of the exchange's signing keys from /keys.  It is 
given
+      // explicitly as the client might otherwise be confused by clock skew as 
to
+      // which signing key was used.
+      exchange_pub: EddsaPublicKey;
+    }
 
-      // Identifies where the product is in stock.
-      address: Location;
 
-      // Identifies when we expect the next restocking to happen.
-      next_restock?: Timestamp;
+Obtaining refunds
+-----------------
 
-    }
+Refunds allow merchants to fully or partially restitute e-cash to a wallet,
+for example because the merchant determined that it could not actually fulfill
+the contract. Refunds must be approved by the merchant's business logic.
 
 
-.. http:post:: /private/products
+.. http:post:: /orders/$ORDER_ID/refund
 
-  This is used to add a product to the inventory.
+  Obtain refunds for an order. After talking to the exchange, the refunds will
+  no longer be pending if processed successfully.
 
   **Request:**
 
-  The request must be a `ProductAddDetail`.
+  The request body is a `WalletRefundRequest` object.
 
   **Response:**
 
+  :status 200 OK:
+    The response is a `WalletRefundResponse`.
   :status 204 No content:
-    The backend has successfully expanded the inventory.
-  :status 409 Conflict:
-    The backend already knows a product with this product ID, but with 
different details.
+    There are no refunds for the order.
+  :status 403 Forbidden:
+    The ``h_contract`` does not match the order.
+  :status 404 Not found:
+    The merchant backend is unaware of the order.
 
+  .. ts:def:: WalletRefundRequest
 
-  .. ts:def:: ProductAddDetail
+    interface WalletRefundRequest {
+      // hash of the order's contract terms (this is used to authenticate the
+      // wallet/customer).
+      h_contract: HashCode;
+    }
 
-    interface ProductAddDetail {
+  .. ts:def:: WalletRefundResponse
 
-      // product ID to use.
-      product_id: string;
+    interface WalletRefundResponse {
+      // Amount that was refunded in total.
+      refund_amount: Amount;
 
-      // Human-readable product description.
-      description: string;
+      // Successful refunds for this payment, empty array for none.
+      refunds: MerchantCoinRefundStatus[];
 
-      // Map from IETF BCP 47 language tags to localized descriptions
-      description_i18n: { [lang_tag: string]: string };
+      // Public key of the merchant.
+      merchant_pub: EddsaPublicKey;
 
-      // unit in which the product is measured (liters, kilograms, packages, 
etc.)
-      unit: string;
+    }
 
-      // The price for one ``unit`` of the product. Zero is used
-      // to imply that this product is not sold separately, or
-      // that the price is not fixed, and must be supplied by the
-      // front-end.  If non-zero, this price MUST include applicable
-      // taxes.
-      price: Amount;
+  .. ts:def:: MerchantCoinRefundStatus
 
-      // An optional base64-encoded product image
-      image: ImageDataUrl;
+    type MerchantCoinRefundStatus =
+      | MerchantCoinRefundSuccessStatus
+      | MerchantCoinRefundFailureStatus;
 
-      // a list of taxes paid by the merchant for one unit of this product
-      taxes: Tax[];
+  .. ts:def:: MerchantCoinRefundFailureStatus
 
-      // Number of units of the product in stock in sum in total,
-      // including all existing sales ever. Given in product-specific
-      // units.
-      // A value of -1 indicates "infinite" (i.e. for "electronic" books).
-      total_stock: Integer;
+    // Details about why a refund failed.
+    interface MerchantCoinRefundFailureStatus {
+      // Used as tag for the sum type RefundStatus sum type.
+      type: "failure";
 
-      // Identifies where the product is in stock.
-      address: Location;
+      // HTTP status of the exchange request, must NOT be 200.
+      exchange_status: Integer;
 
-      // Identifies when we expect the next restocking to happen.
-      next_restock?: Timestamp;
+      // Taler error code from the exchange reply, if available.
+      exchange_code?: Integer;
 
-    }
+      // If available, HTTP reply from the exchange.
+      exchange_reply?: Object;
 
+      // Refund transaction ID.
+      rtransaction_id: Integer;
 
+      // public key of a coin that was refunded
+      coin_pub: EddsaPublicKey;
 
-.. http:patch:: /private/products/$PRODUCT_ID
+      // Amount that was refunded, including refund fee charged by the exchange
+      // to the customer.
+      refund_amount: Amount;
+    }
 
-  This is used to update product details in the inventory. Note that the
-  ``total_stock`` and ``total_lost`` numbers MUST be greater or equal than
-  previous values (this design ensures idempotency).  In case stocks were lost
-  but not sold, increment the ``total_lost`` number.  All fields in the
-  request are optional, those that are not given are simply preserved (not
-  modified).  Note that the ``description_i18n`` and ``taxes`` can only be
-  modified in bulk: if it is given, all translations must be provided, not
-  only those that changed.  "never" should be used for the ``next_restock``
-  timestamp to indicate no intention/possibility of restocking, while a time
-  of zero is used to indicate "unknown".
+  .. ts:def:: MerchantCoinRefundSuccessStatus
 
-  **Request:**
+    // Additional details needed to verify the refund confirmation signature
+    // (``h_contract_terms`` and ``merchant_pub``) are already known
+    // to the wallet and thus not included.
+    interface MerchantCoinRefundSuccessStatus {
+      // Used as tag for the sum type MerchantCoinRefundStatus sum type.
+      type: "success";
 
-  The request must be a `ProductPatchDetail`.
+      // HTTP status of the exchange request, 200 (integer) required for 
refund confirmations.
+      exchange_status: 200;
 
-  **Response:**
+      // the EdDSA :ref:`signature` (binary-only) with purpose
+      // `TALER_SIGNATURE_EXCHANGE_CONFIRM_REFUND` using a current signing key 
of the
+      // exchange affirming the successful refund
+      exchange_sig: EddsaSignature;
 
-  :status 204 No content:
-    The backend has successfully expanded the inventory.
+      // public EdDSA key of the exchange that was used to generate the 
signature.
+      // Should match one of the exchange's signing keys from /keys.  It is 
given
+      // explicitly as the client might otherwise be confused by clock skew as 
to
+      // which signing key was used.
+      exchange_pub: EddsaPublicKey;
 
+      // Refund transaction ID.
+      rtransaction_id: Integer;
 
-  .. ts:def:: ProductPatchDetail
+      // public key of a coin that was refunded
+      coin_pub: EddsaPublicKey;
 
-    interface ProductPatchDetail {
+      // Amount that was refunded, including refund fee charged by the exchange
+      // to the customer.
+      refund_amount: Amount;
+    }
 
-      // Human-readable product description.
-      description: string;
 
-      // Map from IETF BCP 47 language tags to localized descriptions
-      description_i18n: { [lang_tag: string]: string };
+Picking up tips
+---------------
 
-      // unit in which the product is measured (liters, kilograms, packages, 
etc.)
-      unit: string;
+Tips are a way for wallets to obtain e-cash from
+a website.
 
-      // The price for one ``unit`` of the product. Zero is used
-      // to imply that this product is not sold separately, or
-      // that the price is not fixed, and must be supplied by the
-      // front-end.  If non-zero, this price MUST include applicable
-      // taxes.
-      price: Amount;
+.. http:get:: /tips/$TIP_ID
 
-      // An optional base64-encoded product image
-      image: ImageDataUrl;
+  Handle request from wallet to provide details about a tip.
 
-      // a list of taxes paid by the merchant for one unit of this product
-      taxes: Tax[];
+  This endpoint typically also supports requests with the "Accept" header
+  requesting "text/html".  In this case, an HTML response suitable for
+  triggering the interaction with the wallet is returned. If the backend
+  installation does not include the required HTML templates, a 406 status
+  code is returned.
 
-      // Number of units of the product in stock in sum in total,
-      // including all existing sales ever. Given in product-specific
-      // units.
-      // A value of -1 indicates "infinite" (i.e. for "electronic" books).
-      total_stock: Integer;
+  **Response:**
 
-      // Number of units of the product that were lost (spoiled, stolen, etc.)
-      total_lost: Integer;
+  :status 200 OK:
+    A tip is being returned. The backend responds with a `TipInformation`.
+  :status 404 Not Found:
+    The tip identifier is unknown.
+  :status 406 Not Acceptable:
+    The merchant backend could not load the template required to generate a 
reply in the desired format. (Likely HTML templates were not properly 
installed.)
+  :status 410 Gone:
+    A tip has been fully claimed. The JSON reply still contains the 
`TipInformation`.
 
-      // Identifies where the product is in stock.
-      address: Location;
+  .. ts:def:: TipInformation
 
-      // Identifies when we expect the next restocking to happen.
-      next_restock?: Timestamp;
+    interface TipInformation {
 
+      // Exchange from which the tip will be withdrawn. Needed by the
+      // wallet to determine denominations, fees, etc.
+      exchange_url: string;
+
+      // (remaining) amount of the tip (including fees).
+      tip_amount: Amount;
+
+      // Timestamp indicating when the tip is set to expire (may be in the 
past).
+      // Note that tips that have expired MAY also result in a 404 response.
+      expiration: Timestamp;
     }
 
 
+.. http:post:: /tips/$TIP_ID/pickup
 
-.. http:post:: /private/products/$PRODUCT_ID/lock
-
-  This is used to lock a certain quantity of the product for a limited
-  duration while the customer assembles a complete order.  Note that
-  frontends do not have to "unlock", they may rely on the timeout as
-  given in the ``duration`` field.  Re-posting a lock with a different
-  ``duration`` or ``quantity`` updates the existing lock for the same UUID
-  and does not result in a conflict.
-
-  Unlocking by using a ``quantity`` of zero is is
-  optional but recommended if customers remove products from the
-  shopping cart. Note that actually POSTing to ``/orders`` with set
-  ``manage_inventory`` and using ``lock_uuid`` will **transition** the
-  lock to the newly created order (which may have a different ``duration``
-  and ``quantity`` than what was requested in the lock operation).
-  If an order is for fewer items than originally locked, the difference
-  is automatically unlocked.
+  Handle request from wallet to pick up a tip.
 
   **Request:**
 
-  The request must be a `LockRequest`.
+  The request body is a `TipPickupRequest` object.
 
   **Response:**
 
-  :status 204 No content:
-    The backend has successfully locked (or unlocked) the requested 
``quantity``.
-  :status 404 Not found:
-    The backend has does not know this product.
+  :status 200 OK:
+    A tip is being returned. The backend responds with a `TipResponse`
+  :status 401 Unauthorized:
+    The tip amount requested exceeds the tip.
+  :status 404 Not Found:
+    The tip identifier is unknown.
+  :status 409 Conflict:
+    Some of the denomination key hashes of the request do not match those 
currently available from the exchange (hence there is a conflict between what 
the wallet requests and what the merchant believes the exchange can provide).
   :status 410 Gone:
-    The backend does not have enough of product in stock.
+    The tip has expired.
 
-  .. ts:def:: LockRequest
+  .. ts:def:: TipPickupRequest
 
-    interface LockRequest {
+    interface TipPickupRequest {
 
-      // UUID that identifies the frontend performing the lock
-      lock_uuid: UUID;
+      // List of planches the wallet wants to use for the tip
+      planchets: PlanchetDetail[];
+    }
 
-      // How long does the frontend intend to hold the lock
-      duration: RelativeTime;
+  .. ts:def:: PlanchetDetail
 
-      // How many units should be locked?
-      quantity: Integer;
+    interface PlanchetDetail {
+      // Hash of the denomination's public key (hashed to reduce
+      // bandwidth consumption)
+      denom_pub_hash: HashCode;
 
+      // coin's blinded public key
+      coin_ev: CoinEnvelope;
     }
 
+  .. ts:def:: TipResponse
 
-.. http:delete:: /private/products/$PRODUCT_ID
+    interface TipResponse {
 
-  Delete information about a product.  Fails if the product is locked by
-  anyone.
+      // Blind RSA signatures over the planchets.
+      // The order of the signatures matches the planchets list.
+      blind_sigs: BlindSignature[];
+    }
 
-  **Response:**
+  .. ts:def:: BlindSignature
 
-  :status 204 No content:
-    The backend has successfully deleted the product.
-  :status 404 Not found:
-    The backend does not know the instance or the product.
-  :status 409 Conflict:
-    The backend refuses to delete the product because it is locked.
+    interface BlindSignature {
 
+      // The (blind) RSA signature. Still needs to be unblinded.
+      blind_sig: BlindedRsaSignature;
+    }
 
-------------------
-Payment processing
-------------------
 
-.. _post-order:
+-------------------
+Instance management
+-------------------
 
-.. http:post:: /private/orders
+Instances allow one merchant backend to be shared by multiple merchants.
+Every backend must have at least one instance, typcially the "default"
+instance setup before it can be used to manage inventory or process payments.
 
-  Create a new order that a customer can pay for.
 
-  This request is **not** idempotent unless an ``order_id`` is explicitly 
specified.
-  However, while repeating without an ``order_id`` will create another order, 
that is
-  generally pretty harmless (as long as only one of the orders is returned to 
the wallet).
+Setting up instances
+--------------------
 
-  .. note::
+.. http:post:: /private/instances
 
-    This endpoint does not return a URL to redirect your user to confirm the
-    payment.  In order to get this URL use :http:get:/orders/$ORDER_ID.  The
-    API is structured this way since the payment redirect URL is not unique
-    for every order, there might be varying parameters such as the session id.
+  This request will be used to create a new merchant instance in the backend.
 
   **Request:**
 
-  The request must be a `PostOrderRequest`.
+  The request must be a `InstanceConfigurationMessage`.
 
   **Response:**
 
-  :status 200 OK:
-    The backend has successfully created the proposal.  The response is a
-    :ts:type:`PostOrderResponse`.
-  :status 404 Not found:
-    The order given used products from the inventory, but those were not found
-    in the inventory.  Or the merchant instance is unknown (including possibly 
the instance being not configured for new orders).  Details in the
-    error code. NOTE: no good way to find out which product is not in the
-    inventory, we MAY want to specify that in the reply.
+  :status 204 No content:
+    The backend has successfully created the instance.
   :status 409 Conflict:
-    A different proposal already exists under the specified order ID.
-  :status 410 Gone:
-    The order given used products from the inventory that are out of stock.
-    The response is a :ts:type:`OutOfStockResponse`.
-
-
-  .. ts:def:: PostOrderRequest
-
-    interface PostOrderRequest {
-      // The order must at least contain the minimal
-      // order detail, but can override all
-      order: Order;
-
-      // if set, the backend will then set the refund deadline to the current
-      // time plus the specified delay.  If it's not set, refunds will not be
-      // possible.
-      refund_delay?: RelativeTime;
+    This instance already exists, but with other configuration options.
+    Use "PATCH" to update an instance configuration.
 
-      // specifies the payment target preferred by the client. Can be used
-      // to select among the various (active) wire methods supported by the 
instance.
-      payment_target?: string;
+  .. ts:def:: InstanceConfigurationMessage
 
-      // specifies that some products are to be included in the
-      // order from the inventory.  For these inventory management
-      // is performed (so the products must be in stock) and
-      // details are completed from the product data of the backend.
-      inventory_products?: MinimalInventoryProduct[];
+    interface InstanceConfigurationMessage {
+      // The URI where the wallet will send coins.  A merchant may have
+      // multiple accounts, thus this is an array.  Note that by
+      // removing URIs from this list the respective account is set to
+      // inactive and thus unavailable for new contracts, but preserved
+      // in the database as existing offers and contracts may still refer
+      // to it.
+      payto_uris: string[];
 
-      // Specifies a lock identifier that was used to
-      // lock a product in the inventory.  Only useful if
-      // ``manage_inventory`` is set.  Used in case a frontend
-      // reserved quantities of the individual products while
-      // the shopping card was being built.  Multiple UUIDs can
-      // be used in case different UUIDs were used for different
-      // products (i.e. in case the user started with multiple
-      // shopping sessions that were combined during checkout).
-      lock_uuids?: UUID[];
+      // Name of the merchant instance to create (will become $INSTANCE).
+      id: string;
 
-      // Should a token for claiming the order be generated?
-      // False can make sense if the ORDER_ID is sufficiently
-      // high entropy to prevent adversarial claims (like it is
-      // if the backend auto-generates one). Default is 'true'.
-      create_token?: boolean;
+      // Merchant name corresponding to this instance.
+      name: string;
 
-    }
+      // The merchant's physical address (to be put into contracts).
+      address: Location;
 
-  .. ts:def:: Order
+      // The jurisdiction under which the merchant conducts its business
+      // (to be put into contracts).
+      jurisdiction: Location;
 
-    type Order : MinimalOrderDetail | ContractTerms;
+      // Maximum wire fee this instance is willing to pay.
+      // Can be overridden by the frontend on a per-order basis.
+      default_max_wire_fee: Amount;
 
-  The following fields must be specified in the ``order`` field of the 
request.  Other fields from
-  `ContractTerms` are optional, and will override the defaults in the merchant 
configuration.
+      // Default factor for wire fee amortization calculations.
+      // Can be overridden by the frontend on a per-order basis.
+      default_wire_fee_amortization: Integer;
 
-  .. ts:def:: MinimalOrderDetail
+      // Maximum deposit fee (sum over all coins) this instance is willing to 
pay.
+      // Can be overridden by the frontend on a per-order basis.
+      default_max_deposit_fee: Amount;
 
-    interface MinimalOrderDetail {
-      // Amount to be paid by the customer
-      amount: Amount;
+      //  If the frontend does NOT specify an execution date, how long should
+      // we tell the exchange to wait to aggregate transactions before
+      // executing the wire transfer?  This delay is added to the current
+      // time when we generate the advisory execution time for the exchange.
+      default_wire_transfer_delay: RelativeTime;
 
-      // Short summary of the order
-      summary: string;
+      // If the frontend does NOT specify a payment deadline, how long should
+      // offers we make be valid by default?
+      default_pay_delay: RelativeTime;
 
-      // URL that will show that the order was successful after
-      // it has been paid for.  Optional. When POSTing to the
-      // merchant, the placeholder "${ORDER_ID}" will be
-      // replaced with the actual order ID (useful if the
-      // order ID is generated server-side and needs to be
-      // in the URL).
-      fulfillment_url?: string;
     }
 
-  The following fields can be specified if the order is inventory-based.
-  In this case, the backend can compute the amounts from the prices given
-  in the inventory.  Note that if the frontend does give more details
-  (towards the ContractTerms), this will override those details
-  (including total price) that would otherwise computed based on information
-  from the inventory.
 
-  .. ts:def:: ProductSpecification
+.. http:patch:: /private/instances/$INSTANCE
 
-    type ProductSpecification : (MinimalInventoryProduct | Product);
+  Update the configuration of a merchant instance.
 
+  **Request**
 
-  .. ts:def:: MinimalInventoryProduct
+  The request must be a `InstanceReconfigurationMessage`.
+  Removing an existing payto_uri deactivates
+  the account (it will no longer be used for future contracts).
 
-    Note that if the frontend does give details beyond these,
-    it will override those details (including price or taxes)
-    that the backend would otherwise fill in via the inventory.
+  **Response:**
 
-    interface MinimalInventoryProduct {
-      // Which product is requested (here mandatory!)
-      product_id: string;
+  :status 204 No content:
+    The backend has successfully created the instance.
+  :status 404 Not found:
+    This instance is unknown and thus cannot be reconfigured.
 
-      // How many units of the product are requested
-      quantity: Integer;
-    }
+  .. ts:def:: InstanceReconfigurationMessage
 
+    interface InstanceReconfigurationMessage {
+      // The URI where the wallet will send coins.  A merchant may have
+      // multiple accounts, thus this is an array.  Note that by
+      // removing URIs from this list
+      payto_uris: string[];
 
-  .. ts:def:: PostOrderResponse
+      // Merchant name corresponding to this instance.
+      name: string;
 
-    interface PostOrderResponse {
-      // Order ID of the response that was just created
-      order_id: string;
+      // The merchant's physical address (to be put into contracts).
+      address: Location;
 
-      // Token that authorizes the wallet to claim the order.
-      // Provided only if "create_token" was set to 'true'
-      // in the request.
-      token?: ClaimToken;
-    }
+      // The jurisdiction under which the merchant conducts its business
+      // (to be put into contracts).
+      jurisdiction: Location;
 
+      // Maximum wire fee this instance is willing to pay.
+      // Can be overridden by the frontend on a per-order basis.
+      default_max_wire_fee: Amount;
 
-  .. ts:def:: OutOfStockResponse
+      // Default factor for wire fee amortization calculations.
+      // Can be overridden by the frontend on a per-order basis.
+      default_wire_fee_amortization: Integer;
 
-    interface OutOfStockResponse {
-      // Which items are out of stock?
-      missing_products: OutOfStockEntry;
-    }
+      // Maximum deposit fee (sum over all coins) this instance is willing to 
pay.
+      // Can be overridden by the frontend on a per-order basis.
+      default_max_deposit_fee: Amount;
 
-  .. ts:def:: OutOfStockEntry
-
-    interface OutOfStockEntry {
-      // Product ID of an out-of-stock item
-      product_id: string;
-
-      // Requested quantity
-      requested_quantity: Integer;
+      //  If the frontend does NOT specify an execution date, how long should
+      // we tell the exchange to wait to aggregate transactions before
+      // executing the wire transfer?  This delay is added to the current
+      // time when we generate the advisory execution time for the exchange.
+      default_wire_transfer_delay: RelativeTime;
 
-      // Available quantity (must be below ``requested_quanitity``)
-      available_quantity: Integer;
+      // If the frontend does NOT specify a payment deadline, how long should
+      // offers we make be valid by default?
+      default_pay_delay: RelativeTime;
 
-      // When do we expect the product to be again in stock?
-      // Optional, not given if unknown.
-      restock_expected?: Timestamp;
     }
 
 
+Inspecting instances
+--------------------
 
-.. http:get:: /private/orders
-
-  Returns known orders up to some point in the past.
-
-  **Request:**
+.. _instances:
+.. http:get:: /private/instances
 
-  :query paid: *Optional*. If set to yes, only return paid orders, if no only 
unpaid orders. Do not give (or use "all") to see all orders regardless of 
payment status.
-  :query refunded: *Optional*. If set to yes, only return refunded orders, if 
no only unrefunded orders. Do not give (or use "all") to see all orders 
regardless of refund status.
-  :query wired: *Optional*. If set to yes, only return wired orders, if no 
only orders with missing wire transfers. Do not give (or use "all") to see all 
orders regardless of wire transfer status.
-  :query date: *Optional.* Time threshold, see ``delta`` for its 
interpretation.  Defaults to the oldest or most recent entry, depending on 
``delta``.
-  :query start: *Optional*. Row number threshold, see ``delta`` for its 
interpretation.  Defaults to ``UINT64_MAX``, namely the biggest row id possible 
in the database.
-  :query delta: *Optional*. takes value of the form ``N (-N)``, so that at 
most ``N`` values strictly older (younger) than ``start`` and ``date`` are 
returned.  Defaults to ``-20`` to return the last 20 entries (before ``start`` 
and/or ``date``).
-  :query timeout_ms: *Optional*. Timeout in milli-seconds to wait for 
additional orders if the answer would otherwise be negative (long polling). 
Only useful if delta is positive. Note that the merchant MAY still return a 
response that contains fewer than delta orders.
+  This is used to return the list of all the merchant instances
 
   **Response:**
 
   :status 200 OK:
-    The response is an `OrderHistory`.
+    The backend has successfully returned the list of instances stored. Returns
+    a `InstancesResponse`.
 
-  .. ts:def:: OrderHistory
+  .. ts:def:: InstancesResponse
 
-    interface OrderHistory {
-      // timestamp-sorted array of all orders matching the query.
-      // The order of the sorting depends on the sign of ``delta``.
-      orders : OrderHistoryEntry[];
+    interface InstancesResponse {
+      // List of instances that are present in the backend (see `Instance`)
+      instances: Instance[];
     }
 
+  The `Instance` object describes the instance registered with the backend.
+  It does not include the full details, only those that usually concern the 
frontend.
+  It has the following structure:
 
-  .. ts:def:: OrderHistoryEntry
+  .. ts:def:: Instance
 
-    interface OrderHistoryEntry {
+    interface Instance {
+      // Merchant name corresponding to this instance.
+      name: string;
 
-      // order ID of the transaction related to this entry.
-      order_id: string;
+      // Merchant instance this response is about ($INSTANCE)
+      id: string;
 
-      // row ID of the order in the database
-      row_id: number;
+      // Public key of the merchant/instance, in Crockford Base32 encoding.
+      merchant_pub: EddsaPublicKey;
 
-      // when the order was created
-      timestamp: Timestamp;
+      // List of the payment targets supported by this instance. Clients can
+      // specify the desired payment target in /order requests.  Note that
+      // front-ends do not have to support wallets selecting payment targets.
+      payment_targets: string[];
 
-      // the amount of money the order is for
-      amount: Amount;
+   }
 
-      // the summary of the order
-      summary: string;
 
-      // whether some part of the order is refundable,
-      // that is the refund deadline has not yet expired
-      // and the total amount refunded so far is below
-      // the value of the original transaction.
-      refundable: boolean;
+.. http:get:: /private/instances/$INSTANCE
 
-      // whether the order has been paid or not
-      paid: boolean;
-    }
+  This is used to query a specific merchant instance.
 
+  **Response:**
 
+  :status 200 OK:
+    The backend has successfully returned the list of instances stored. Returns
+    a `QueryInstancesResponse`.
 
-.. http:post:: /orders/$ORDER_ID/claim
+  .. ts:def:: QueryInstancesResponse
 
-  Wallet claims ownership (via nonce) over an order.  By claiming
-  an order, the wallet obtains the full contract terms, and thereby
-  implicitly also the hash of the contract terms it needs for the
-  other ``/public/`` APIs to authenticate itself as the wallet that
-  is indeed eligible to inspect this particular order's status.
+    interface QueryInstancesResponse {
+      // The URI where the wallet will send coins.  A merchant may have
+      // multiple accounts, thus this is an array.
+      accounts: MerchantAccount[];
 
-  **Request:**
+      // Merchant name corresponding to this instance.
+      name: string;
 
-  The request must be a `ClaimRequest`
+      // Public key of the merchant/instance, in Crockford Base32 encoding.
+      merchant_pub: EddsaPublicKey;
 
-  .. ts:def:: ClaimRequest
+      // The merchant's physical address (to be put into contracts).
+      address: Location;
 
-    interface ClaimRequest {
-      // Nonce to identify the wallet that claimed the order.
-      nonce: string;
+      // The jurisdiction under which the merchant conducts its business
+      // (to be put into contracts).
+      jurisdiction: Location;
+
+      // Maximum wire fee this instance is willing to pay.
+      // Can be overridden by the frontend on a per-order basis.
+      default_max_wire_fee: Amount;
+
+      // Default factor for wire fee amortization calculations.
+      // Can be overridden by the frontend on a per-order basis.
+      default_wire_fee_amortization: Integer;
+
+      // Maximum deposit fee (sum over all coins) this instance is willing to 
pay.
+      // Can be overridden by the frontend on a per-order basis.
+      default_max_deposit_fee: Amount;
+
+      //  If the frontend does NOT specify an execution date, how long should
+      // we tell the exchange to wait to aggregate transactions before
+      // executing the wire transfer?  This delay is added to the current
+      // time when we generate the advisory execution time for the exchange.
+      default_wire_transfer_delay: RelativeTime;
+
+      // If the frontend does NOT specify a payment deadline, how long should
+      // offers we make be valid by default?
+      default_pay_deadline: RelativeTime;
 
-      // Token that authorizes the wallet to claim the order.
-      // *Optional* as the merchant may not have required it
-      // (``create_token`` set to ``false`` in `PostOrderRequest`).
-      token?: ClaimToken;
     }
 
-  **Response:**
+  .. ts:def:: MerchantAccount
 
-  :status 200 OK:
-    The client has successfully claimed the order.
-    The response contains the :ref:`contract terms <contract-terms>`.
-  :status 404 Not found:
-    The backend is unaware of the instance or order.
-  :status 409 Conflict:
-    The someone else claimed the same order ID with different nonce before.
+    interface MerchantAccount {
 
-  .. ts:def:: ClaimResponse
+      // payto:// URI of the account.
+      payto_uri: string;
 
-    interface ClaimResponse {
-      // Contract terms of the claimed order
-      contract_terms: ContractTerms;
+      // Hash over the wire details (including over the salt)
+      h_wire: HashCode;
 
-      // Signature by the merchant over the contract terms.
-      sig: EddsaSignature;
+      // salt used to compute h_wire
+      salt: HashCode;
+
+      // true if this account is active,
+      // false if it is historic.
+      active: boolean;
     }
 
+    
+Deleting instances
+------------------
 
-.. http:post:: /orders/$ORDER_ID/pay
+.. http:delete:: /private/instances/$INSTANCE
 
-  Pay for an order by giving a deposit permission for coins.  Typically used by
-  the customer's wallet.  Note that this request does not include the
-  usual ``h_contract`` argument to authenticate the wallet, as the hash of
-  the contract is implied by the signatures of the coins.  Furthermore, this
-  API doesn't really return useful information about the order.
+  This request will be used to delete (permanently disable)
+  or purge merchant instance in the backend. Purging will
+  delete all offers and payments associated with the instance,
+  while disabling (the default) only deletes the private key
+  and makes the instance unusable for new orders or payments.
 
   **Request:**
 
-  The request must be a `pay request <PayRequest>`.
+  :query purge: *Optional*. If set to YES, the instance will be fully
+      deleted. Otherwise only the private key would be deleted.
 
-  **Response:**
+  **Response**
 
-  :status 200 OK:
-    The exchange accepted all of the coins.
-    The body is a `payment response <PaymentResponse>`.
-    The ``frontend`` should now fulfill the contract.
-    Note that it is possible that refunds have been granted.
-  :status 400 Bad request:
-    Either the client request is malformed or some specific processing error
-    happened that may be the fault of the client as detailed in the JSON body
-    of the response.
-  :status 402 Payment required:
-    There used to be a sufficient payment, but due to refunds the amount 
effectively
-    paid is no longer sufficient. (If the amount is generally insufficient, we
-    return "406 Not Acceptable", only if this is because of refunds we return 
402.)
-  :status 403 Forbidden:
-    One of the coin signatures was not valid.
+  :status 204 No content:
+    The backend has successfully removed the instance.  The body is empty.
   :status 404 Not found:
-    The merchant backend could not find the order or the instance and thus 
cannot process the payment.
-  :status 406 Not Acceptable:
-    The payment is insufficient (sum is below the required total amount).
-  :status 408 Request Timeout:
-    The backend took too long to process the request. Likely the merchant's 
connection
-    to the exchange timed out. Try again.
+    The instance is unknown to the backend.
   :status 409 Conflict:
-    The exchange rejected the payment because a coin was already spent before.
-    The response will include the ``coin_pub`` for which the payment failed,
-    in addition to the response from the exchange to the ``/deposit`` request.
-  :status 410 Gone:
-    The offer has expired and is no longer available.
-  :status 412 Precondition Failed:
-    The given exchange is not acceptable for this merchant, as it is not in the
-    list of accepted exchanges and not audited by an approved auditor.
-  :status 424 Failed Dependency:
-    The merchant's interaction with the exchange failed in some way.
-    The client might want to try later again.
-    This includes failures like the denomination key of a coin not being
-    known to the exchange as far as the merchant can tell.
+    The instance cannot be deleted because it has pending offers, or
+    the instance cannot be purged because it has successfully processed
+    payments that have not passed the TAX_RECORD_EXPIRATION time.
+    The latter case only applies if ``purge`` was set.
 
-  The backend will return verbatim the error codes received from the exchange's
-  :ref:`deposit <deposit>` API.  If the wallet made a mistake, like by
-  double-spending for example, the frontend should pass the reply verbatim to
-  the browser/wallet.  If the payment was successful, the frontend MAY use
-  this to trigger some business logic.
 
-  .. ts:def:: PaymentResponse
+--------------------
+Inventory management
+--------------------
 
-    interface PaymentResponse {
-      // Signature on ``TALER_PaymentResponsePS`` with the public
-      // key of the merchant instance.
-      sig: EddsaSignature;
+.. _inventory:
 
-    }
+Inventory management is an *optional* backend feature that can be used to
+manage limited stocks of products and to auto-complete product descriptions in
+contracts (such that the frontends have to do less work).  You can use the
+Taler merchant backend to process payments *without* using its inventory
+management.
 
-  .. ts:def:: PayRequest
 
-    interface PayRequest {
-      // The coins used to make the payment.
-      coins: CoinPaySig[];
+Adding products to the inventory
+--------------------------------
 
-      // The session for which the payment is made (or replayed).
-      // Only set for session-based payments.
-      session_id?: string;
+.. http:post:: /private/products
 
-    }
+  This is used to add a product to the inventory.
 
-  .. ts:def:: CoinPaySig
+  **Request:**
 
-    export interface CoinPaySig {
-      // Signature by the coin.
-      coin_sig: EddsaSignature;
+  The request must be a `ProductAddDetail`.
 
-      // Public key of the coin being spend.
-      coin_pub: EddsaPublicKey;
+  **Response:**
 
-      // Signature made by the denomination public key.
-      ub_sig: RsaSignature;
+  :status 204 No content:
+    The backend has successfully expanded the inventory.
+  :status 409 Conflict:
+    The backend already knows a product with this product ID, but with 
different details.
 
-      // The hash of the denomination public key associated with this coin.
-      h_denom: HashCode;
 
-      // The amount that is subtracted from this coin with this payment.
-      contribution: Amount;
+  .. ts:def:: ProductAddDetail
+
+    interface ProductAddDetail {
+
+      // product ID to use.
+      product_id: string;
+
+      // Human-readable product description.
+      description: string;
+
+      // Map from IETF BCP 47 language tags to localized descriptions
+      description_i18n: { [lang_tag: string]: string };
+
+      // unit in which the product is measured (liters, kilograms, packages, 
etc.)
+      unit: string;
+
+      // The price for one ``unit`` of the product. Zero is used
+      // to imply that this product is not sold separately, or
+      // that the price is not fixed, and must be supplied by the
+      // front-end.  If non-zero, this price MUST include applicable
+      // taxes.
+      price: Amount;
+
+      // An optional base64-encoded product image
+      image: ImageDataUrl;
+
+      // a list of taxes paid by the merchant for one unit of this product
+      taxes: Tax[];
+
+      // Number of units of the product in stock in sum in total,
+      // including all existing sales ever. Given in product-specific
+      // units.
+      // A value of -1 indicates "infinite" (i.e. for "electronic" books).
+      total_stock: Integer;
+
+      // Identifies where the product is in stock.
+      address: Location;
+
+      // Identifies when we expect the next restocking to happen.
+      next_restock?: Timestamp;
 
-      // URL of the exchange this coin was withdrawn from.
-      exchange_url: string;
     }
 
 
-.. http:post:: /orders/$ORDER_ID/paid
 
-  Prove that the client previously paid for an order by providing
-  the merchant's signature from the `payment response <PaymentResponse>`.
-  Typically used by the customer's wallet if it receives a request for
-  payment for an order that it already paid. This is more compact then
-  re-transmitting the full payment details.
-  Note that this request does include the
-  usual ``h_contract`` argument to authenticate the wallet and
-  to allow the merchant to verify the signature before checking
-  with its own database.
+.. http:patch:: /private/products/$PRODUCT_ID
+
+  This is used to update product details in the inventory. Note that the
+  ``total_stock`` and ``total_lost`` numbers MUST be greater or equal than
+  previous values (this design ensures idempotency).  In case stocks were lost
+  but not sold, increment the ``total_lost`` number.  All fields in the
+  request are optional, those that are not given are simply preserved (not
+  modified).  Note that the ``description_i18n`` and ``taxes`` can only be
+  modified in bulk: if it is given, all translations must be provided, not
+  only those that changed.  "never" should be used for the ``next_restock``
+  timestamp to indicate no intention/possibility of restocking, while a time
+  of zero is used to indicate "unknown".
 
   **Request:**
 
-  The request must be a `paid request <PaidRequest>`.
+  The request must be a `ProductPatchDetail`.
 
   **Response:**
 
   :status 204 No content:
-    The merchant accepted the signature.
-    The ``frontend`` should now fulfill the contract.
-    Note that it is possible that refunds have been granted.
-  :status 400 Bad request:
-    Either the client request is malformed or some specific processing error
-    happened that may be the fault of the client as detailed in the JSON body
-    of the response.
-  :status 403 Forbidden:
-    The signature was not valid.
+    The backend has successfully expanded the inventory.
+
+
+  .. ts:def:: ProductPatchDetail
+
+    interface ProductPatchDetail {
+
+      // Human-readable product description.
+      description: string;
+
+      // Map from IETF BCP 47 language tags to localized descriptions
+      description_i18n: { [lang_tag: string]: string };
+
+      // unit in which the product is measured (liters, kilograms, packages, 
etc.)
+      unit: string;
+
+      // The price for one ``unit`` of the product. Zero is used
+      // to imply that this product is not sold separately, or
+      // that the price is not fixed, and must be supplied by the
+      // front-end.  If non-zero, this price MUST include applicable
+      // taxes.
+      price: Amount;
+
+      // An optional base64-encoded product image
+      image: ImageDataUrl;
+
+      // a list of taxes paid by the merchant for one unit of this product
+      taxes: Tax[];
+
+      // Number of units of the product in stock in sum in total,
+      // including all existing sales ever. Given in product-specific
+      // units.
+      // A value of -1 indicates "infinite" (i.e. for "electronic" books).
+      total_stock: Integer;
+
+      // Number of units of the product that were lost (spoiled, stolen, etc.)
+      total_lost: Integer;
+
+      // Identifies where the product is in stock.
+      address: Location;
+
+      // Identifies when we expect the next restocking to happen.
+      next_restock?: Timestamp;
+
+    }
+
+Inspecting inventory
+--------------------
+
+.. http:get:: /private/products
+
+  This is used to return the list of all items in the inventory.
+
+  **Response:**
+
+  :status 200 OK:
+    The backend has successfully returned the inventory. Returns
+    a `InventorySummaryResponse`.
+
+  .. ts:def:: InventorySummaryResponse
+
+    interface InventorySummaryResponse {
+      // List of products that are present in the inventory
+      products: InventoryEntry[];
+    }
+
+  The `InventoryEntry` object describes an item in the inventory. It has the 
following structure:
+
+  .. ts:def:: InventoryEntry
+
+    interface InventoryEntry {
+      // Product identifier, as found in the product.
+      product_id: string;
+
+    }
+
+
+.. http:get:: /private/products/$PRODUCT_ID
+
+  This is used to obtain detailed information about a product in the inventory.
+
+  **Response:**
+
+  :status 200 OK:
+    The backend has successfully returned the inventory. Returns
+    a `ProductDetail`.
+
+  .. ts:def:: ProductDetail
+
+    interface ProductDetail {
+
+      // Human-readable product description.
+      description: string;
+
+      // Map from IETF BCP 47 language tags to localized descriptions
+      description_i18n: { [lang_tag: string]: string };
+
+      // unit in which the product is measured (liters, kilograms, packages, 
etc.)
+      unit: string;
+
+      // The price for one ``unit`` of the product. Zero is used
+      // to imply that this product is not sold separately, or
+      // that the price is not fixed, and must be supplied by the
+      // front-end.  If non-zero, this price MUST include applicable
+      // taxes.
+      price: Amount;
+
+      // An optional base64-encoded product image
+      image: ImageDataUrl;
+
+      // a list of taxes paid by the merchant for one unit of this product
+      taxes: Tax[];
+
+      // Number of units of the product in stock in sum in total,
+      // including all existing sales ever. Given in product-specific
+      // units.
+      // A value of -1 indicates "infinite" (i.e. for "electronic" books).
+      total_stock: Integer;
+
+      // Number of units of the product that have already been sold.
+      total_sold: Integer;
+
+      // Number of units of the product that were lost (spoiled, stolen, etc.)
+      total_lost: Integer;
+
+      // Identifies where the product is in stock.
+      address: Location;
+
+      // Identifies when we expect the next restocking to happen.
+      next_restock?: Timestamp;
+
+    }
+
+
+Reserving inventory
+-------------------
+
+.. http:post:: /private/products/$PRODUCT_ID/lock
+
+  This is used to lock a certain quantity of the product for a limited
+  duration while the customer assembles a complete order.  Note that
+  frontends do not have to "unlock", they may rely on the timeout as
+  given in the ``duration`` field.  Re-posting a lock with a different
+  ``duration`` or ``quantity`` updates the existing lock for the same UUID
+  and does not result in a conflict.
+
+  Unlocking by using a ``quantity`` of zero is is
+  optional but recommended if customers remove products from the
+  shopping cart. Note that actually POSTing to ``/orders`` with set
+  ``manage_inventory`` and using ``lock_uuid`` will **transition** the
+  lock to the newly created order (which may have a different ``duration``
+  and ``quantity`` than what was requested in the lock operation).
+  If an order is for fewer items than originally locked, the difference
+  is automatically unlocked.
+
+  **Request:**
+
+  The request must be a `LockRequest`.
+
+  **Response:**
+
+  :status 204 No content:
+    The backend has successfully locked (or unlocked) the requested 
``quantity``.
   :status 404 Not found:
-    The merchant backend could not find the order or the instance
-    and thus cannot process the request.
-  :status 409 Conflict:
-    The provided contract hash does not match this order.
+    The backend has does not know this product.
+  :status 410 Gone:
+    The backend does not have enough of product in stock.
 
-  .. ts:def:: PaidRequest
+  .. ts:def:: LockRequest
 
-    interface PaidRequest {
-      // Signature on ``TALER_PaymentResponsePS`` with the public
-      // key of the merchant instance.
-      sig: EddsaSignature;
+    interface LockRequest {
 
-      // hash of the order's contract terms (this is used to authenticate the
-      // wallet/customer and to enable signature verification without
-      // database access).
-      h_contract: HashCode;
+      // UUID that identifies the frontend performing the lock
+      lock_uuid: UUID;
+
+      // How long does the frontend intend to hold the lock
+      duration: RelativeTime;
+
+      // How many units should be locked?
+      quantity: Integer;
 
-      // Session id for which the payment is proven.
-      session_id: string;
     }
 
-.. _order-abort:
-.. http:post:: /orders/$ORDER_ID/abort
+Removing products from inventory
+--------------------------------
 
-  Abort paying for an order and obtain a refund for coins that
-  were already deposited as part of a failed payment.
+.. http:delete:: /private/products/$PRODUCT_ID
+
+  Delete information about a product.  Fails if the product is locked by
+  anyone.
+
+  **Response:**
+
+  :status 204 No content:
+    The backend has successfully deleted the product.
+  :status 404 Not found:
+    The backend does not know the instance or the product.
+  :status 409 Conflict:
+    The backend refuses to delete the product because it is locked.
+
+
+------------------
+Payment processing
+------------------
+
+To process Taler payments, a merchant must first setup an order with
+the merchant backend. The order is then claimed by a wallet, and
+paid by the wallet. The merchant can check the payment status of the
+order. Once the order is paid, the merchant may (for a limited time)
+grant refunds on the order.
+
+Creating orders
+---------------
+
+.. _post-order:
+
+.. http:post:: /private/orders
+
+  Create a new order that a customer can pay for.
+
+  This request is **not** idempotent unless an ``order_id`` is explicitly 
specified.
+  However, while repeating without an ``order_id`` will create another order, 
that is
+  generally pretty harmless (as long as only one of the orders is returned to 
the wallet).
+
+  .. note::
+
+    This endpoint does not return a URL to redirect your user to confirm the
+    payment.  In order to get this URL use :http:get:/orders/$ORDER_ID.  The
+    API is structured this way since the payment redirect URL is not unique
+    for every order, there might be varying parameters such as the session id.
 
   **Request:**
 
-  The request must be an `abort request <AbortRequest>`.  We force the wallet
-  to specify the affected coins as it may only request for a subset of the 
coins
-  (i.e. because the wallet knows that some were double-spent causing the 
failure).
-  Also we need to know the coins because there may be two wallets "competing" 
over
-  the same order and one wants to abort while the other still proceeds with the
-  payment. Here we need to again know which subset of the deposits to abort.
+  The request must be a `PostOrderRequest`.
 
   **Response:**
 
   :status 200 OK:
-    The merchant accepted the request, and passed it on to the exchange. The 
body is a
-    a `merchant refund response <MerchantRefundResponse>`. Note that the 
exchange
-    MAY still have encountered errors in processing. Those will then be part of
-    the body. Wallets MUST carefully consider errors for each of the coins as
-    returned by the exchange.
-  :status 400 Bad request:
-    Either the client request is malformed or some specific processing error
-    happened that may be the fault of the client as detailed in the JSON body
-    of the response.
-  :status 403 Forbidden:
-    The ``h_contract`` does not match the $ORDER_ID.
+    The backend has successfully created the proposal.  The response is a
+    :ts:type:`PostOrderResponse`.
   :status 404 Not found:
-    The merchant backend could not find the order or the instance
-    and thus cannot process the abort request.
-  :status 408 Request Timeout:
-    The merchant backend took too long getting a response from the exchange.
-    The wallet SHOULD retry soon.
-  :status 412 Precondition Failed:
-    Aborting the payment is not allowed, as the original payment did succeed.
-    It is possible that a different wallet succeeded with the payment. This
-    wallet should thus try to refresh all of the coins involved in the payment.
-  :status 424 Failed Dependency:
-    The merchant's interaction with the exchange failed in some way.
-    The error from the exchange is included.
+    The order given used products from the inventory, but those were not found
+    in the inventory.  Or the merchant instance is unknown (including possibly 
the instance being not configured for new orders).  Details in the
+    error code. NOTE: no good way to find out which product is not in the
+    inventory, we MAY want to specify that in the reply.
+  :status 409 Conflict:
+    A different proposal already exists under the specified order ID.
+  :status 410 Gone:
+    The order given used products from the inventory that are out of stock.
+    The response is a :ts:type:`OutOfStockResponse`.
 
-  The backend will return an `abort response <AbortResponse>`, which includes
-  verbatim the error codes received from the exchange's
-  :ref:`refund <exchange_refund>` API.  The frontend should pass the replies 
verbatim to
-  the browser/wallet.
 
-  .. ts:def:: AbortRequest
+  .. ts:def:: PostOrderRequest
+
+    interface PostOrderRequest {
+      // The order must at least contain the minimal
+      // order detail, but can override all
+      order: Order;
+
+      // if set, the backend will then set the refund deadline to the current
+      // time plus the specified delay.  If it's not set, refunds will not be
+      // possible.
+      refund_delay?: RelativeTime;
+
+      // specifies the payment target preferred by the client. Can be used
+      // to select among the various (active) wire methods supported by the 
instance.
+      payment_target?: string;
+
+      // specifies that some products are to be included in the
+      // order from the inventory.  For these inventory management
+      // is performed (so the products must be in stock) and
+      // details are completed from the product data of the backend.
+      inventory_products?: MinimalInventoryProduct[];
+
+      // Specifies a lock identifier that was used to
+      // lock a product in the inventory.  Only useful if
+      // ``manage_inventory`` is set.  Used in case a frontend
+      // reserved quantities of the individual products while
+      // the shopping card was being built.  Multiple UUIDs can
+      // be used in case different UUIDs were used for different
+      // products (i.e. in case the user started with multiple
+      // shopping sessions that were combined during checkout).
+      lock_uuids?: UUID[];
+
+      // Should a token for claiming the order be generated?
+      // False can make sense if the ORDER_ID is sufficiently
+      // high entropy to prevent adversarial claims (like it is
+      // if the backend auto-generates one). Default is 'true'.
+      create_token?: boolean;
+
+    }
+
+  .. ts:def:: Order
+
+    type Order : MinimalOrderDetail | ContractTerms;
+
+  The following fields must be specified in the ``order`` field of the 
request.  Other fields from
+  `ContractTerms` are optional, and will override the defaults in the merchant 
configuration.
+
+  .. ts:def:: MinimalOrderDetail
+
+    interface MinimalOrderDetail {
+      // Amount to be paid by the customer
+      amount: Amount;
+
+      // Short summary of the order
+      summary: string;
+
+      // URL that will show that the order was successful after
+      // it has been paid for.  Optional. When POSTing to the
+      // merchant, the placeholder "${ORDER_ID}" will be
+      // replaced with the actual order ID (useful if the
+      // order ID is generated server-side and needs to be
+      // in the URL).
+      fulfillment_url?: string;
+    }
+
+  The following fields can be specified if the order is inventory-based.
+  In this case, the backend can compute the amounts from the prices given
+  in the inventory.  Note that if the frontend does give more details
+  (towards the ContractTerms), this will override those details
+  (including total price) that would otherwise computed based on information
+  from the inventory.
 
-    interface AbortRequest {
+  .. ts:def:: ProductSpecification
 
-      // hash of the order's contract terms (this is used to authenticate the
-      // wallet/customer in case $ORDER_ID is guessable).
-      h_contract: HashCode;
+    type ProductSpecification : (MinimalInventoryProduct | Product);
 
-      // List of coins the wallet would like to see refunds for.
-      // (Should be limited to the coins for which the original
-      // payment succeeded, as far as the wallet knows.)
-      coins: AbortingCoin[];
-    }
 
-  .. ts:def:: AbortingCoin
+  .. ts:def:: MinimalInventoryProduct
 
-    interface AbortingCoin {
-      // Public key of a coin for which the wallet is requesting an 
abort-related refund.
-      coin_pub: EddsaPublicKey;
+    Note that if the frontend does give details beyond these,
+    it will override those details (including price or taxes)
+    that the backend would otherwise fill in via the inventory.
 
-      // The amount to be refunded (matches the original contribution)
-      contribution: Amount;
+    interface MinimalInventoryProduct {
+      // Which product is requested (here mandatory!)
+      product_id: string;
 
-      // URL of the exchange this coin was withdrawn from.
-      exchange_url: string;
+      // How many units of the product are requested
+      quantity: Integer;
     }
 
 
-  .. ts:def:: AbortResponse
+  .. ts:def:: PostOrderResponse
 
-    interface AbortResponse {
+    interface PostOrderResponse {
+      // Order ID of the response that was just created
+      order_id: string;
 
-      // List of refund responses about the coins that the wallet
-      // requested an abort for.  In the same order as the 'coins'
-      // from the original request.
-      // The rtransaction_id is implied to be 0.
-      refunds: MerchantAbortPayRefundStatus[];
+      // Token that authorizes the wallet to claim the order.
+      // Provided only if "create_token" was set to 'true'
+      // in the request.
+      token?: ClaimToken;
     }
 
-  .. ts:def:: MerchantAbortPayRefundStatus
 
-    type MerchantAbortPayRefundStatus =
-      | MerchantAbortPayRefundSuccessStatus
-      | MerchantAbortPayRefundFailureStatus;
+  .. ts:def:: OutOfStockResponse
 
-  .. ts:def:: MerchantAbortPayRefundFailureStatus
+    interface OutOfStockResponse {
 
-    // Details about why a refund failed.
-    interface MerchantAbortPayRefundFailureStatus {
-      // Used as tag for the sum type RefundStatus sum type.
-      type: "failure"
+      // Product ID of an out-of-stock item
+      product_id: string;
 
-      // HTTP status of the exchange request, must NOT be 200.
-      exchange_status: Integer;
+      // Requested quantity
+      requested_quantity: Integer;
 
-      // Taler error code from the exchange reply, if available.
-      exchange_code?: Integer;
+      // Available quantity (must be below ``requested_quanitity``)
+      available_quantity: Integer;
 
-      // If available, HTTP reply from the exchange.
-      exchange_reply?: Object;
+      // When do we expect the product to be again in stock?
+      // Optional, not given if unknown.
+      restock_expected?: Timestamp;
     }
 
-  .. ts:def:: MerchantAbortPayRefundSuccessStatus
 
-    // Additional details needed to verify the refund confirmation signature
-    // (``h_contract_terms`` and ``merchant_pub``) are already known
-    // to the wallet and thus not included.
-    interface MerchantAbortPayRefundSuccessStatus {
-      // Used as tag for the sum type MerchantCoinRefundStatus sum type.
-      type: "success"
+Inspecting orders
+-----------------
 
-      // HTTP status of the exchange request, 200 (integer) required for 
refund confirmations.
-      exchange_status: 200;
+.. http:get:: /private/orders
 
-      // the EdDSA :ref:`signature` (binary-only) with purpose
-      // `TALER_SIGNATURE_EXCHANGE_CONFIRM_REFUND` using a current signing key 
of the
-      // exchange affirming the successful refund
-      exchange_sig: EddsaSignature;
+  Returns known orders up to some point in the past.
 
-      // public EdDSA key of the exchange that was used to generate the 
signature.
-      // Should match one of the exchange's signing keys from /keys.  It is 
given
-      // explicitly as the client might otherwise be confused by clock skew as 
to
-      // which signing key was used.
-      exchange_pub: EddsaPublicKey;
-    }
+  **Request:**
 
+  :query paid: *Optional*. If set to yes, only return paid orders, if no only 
unpaid orders. Do not give (or use "all") to see all orders regardless of 
payment status.
+  :query refunded: *Optional*. If set to yes, only return refunded orders, if 
no only unrefunded orders. Do not give (or use "all") to see all orders 
regardless of refund status.
+  :query wired: *Optional*. If set to yes, only return wired orders, if no 
only orders with missing wire transfers. Do not give (or use "all") to see all 
orders regardless of wire transfer status.
+  :query date: *Optional.* Time threshold, see ``delta`` for its 
interpretation.  Defaults to the oldest or most recent entry, depending on 
``delta``.
+  :query start: *Optional*. Row number threshold, see ``delta`` for its 
interpretation.  Defaults to ``UINT64_MAX``, namely the biggest row id possible 
in the database.
+  :query delta: *Optional*. takes value of the form ``N (-N)``, so that at 
most ``N`` values strictly older (younger) than ``start`` and ``date`` are 
returned.  Defaults to ``-20`` to return the last 20 entries (before ``start`` 
and/or ``date``).
+  :query timeout_ms: *Optional*. Timeout in milli-seconds to wait for 
additional orders if the answer would otherwise be negative (long polling). 
Only useful if delta is positive. Note that the merchant MAY still return a 
response that contains fewer than delta orders.
 
-.. http:patch:: /private/orders/$ORDER_ID/forget
+  **Response:**
 
-  Forget fields in an order's contract terms that the merchant no
-  longer needs.
+  :status 200 OK:
+    The response is an `OrderHistory`.
 
-  **Request:**
+  .. ts:def:: OrderHistory
 
-  The request must be a `forget request <ForgetRequest>`. The fields specified
-  must have been marked as forgettable when the contract was created. Fields in
-  the request that are not in the `contract terms <ContractTerms>` are ignored.
+    interface OrderHistory {
+      // timestamp-sorted array of all orders matching the query.
+      // The order of the sorting depends on the sign of ``delta``.
+      orders : OrderHistoryEntry[];
+    }
 
-  A valid
-  JSON path is defined as a string beginning with ``$.`` that follows the dot
-  notation: ``$.wire_fee``, for example. The ``$`` represents the `contract 
terms <ContractTerms>`
-  object, and an identifier following a ``.`` represents the field of that
-  identifier belonging to the object preceding the dot. Arrays can be indexed
-  by an non-negative integer within brackets: ``$.products[1]``. An asterisk 
``*``
-  can be used to index an array as a wildcard, which expands the path into a
-  list of paths containing one path for
-  each valid array index: ``$.products[*].description``. For a path to be 
valid,
-  it must end with a reference to a field of an object (it cannot end with an
-  array index or wildcard).
 
-  **Response:**
+  .. ts:def:: OrderHistoryEntry
 
-  :status 200 OK:
-    The merchant deleted the specified fields from the contract of
-    order $ORDER_ID.
-  :status 400 Bad request:
-    The request is malformed or one of the paths is invalid.
-  :status 404 Not found:
-    The merchant backend could not find the order or the instance
-    and thus cannot process the abort request.
-  :status 409 Conflict:
-    The request includes a field that was not marked as forgettable, so
-    the merchant cannot delete that field.
+    interface OrderHistoryEntry {
 
-  .. ts:def:: ForgetRequest
+      // order ID of the transaction related to this entry.
+      order_id: string;
 
-    interface ForgetRequest {
+      // row ID of the order in the database
+      row_id: number;
 
-      // Array of valid JSON paths to forgettable fields in the order's
-      // contract terms.
-      fields: string[];
-    }
+      // when the order was created
+      timestamp: Timestamp;
 
+      // the amount of money the order is for
+      amount: Amount;
+
+      // the summary of the order
+      summary: string;
+
+      // whether some part of the order is refundable,
+      // that is the refund deadline has not yet expired
+      // and the total amount refunded so far is below
+      // the value of the original transaction.
+      refundable: boolean;
+
+      // whether the order has been paid or not
+      paid: boolean;
+    }
 
 .. http:get:: /private/orders/$ORDER_ID
 
@@ -1404,101 +1760,62 @@ Payment processing
       coin_pub: CoinPublicKey;
     }
 
+    
 
+Private order data cleanup
+--------------------------
 
-.. http:get:: /orders/$ORDER_ID
-
-  Query the payment status of an order. This endpoint is for the wallet.
-  When the wallet goes to this URL and it is unpaid,
-  they will be prompted for payment.
-  This endpoint typically also supports requests with the "Accept" header
-  requesting "text/html".  In this case, an HTML response suitable for
-  triggering the interaction with the wallet is returned, with ``timeout_ms``
-  ignored (treated as zero). If the backend installation does not include the
-  required HTML templates, a 406 status code is returned.
-
-  In the case that the request was made with a claim token (even the wrong one)
-  and the order was claimed and paid, the server will redirect the client to
-  the fulfillment URL.  This redirection will happen with a 302 status code
-  if the "Accept" header specified "text/html", and with a 202 status code
-  otherwise.
-
-  **Request:**
-
-  :query h_contract=HASH: hash of the order's contract terms (this is used to 
authenticate the wallet/customer in case $ORDER_ID is guessable). Required once 
an order was claimed.
-  :query token=TOKEN: *Optional*. Authorizes the request via the claim token 
that was returned  in the `PostOrderResponse`.  Used with unclaimed orders 
only. Whether token authorization is required is determined by the merchant 
when the frontend creates the order.
-  :query session_id=STRING: *Optional*. Session ID that the payment must be 
bound to.  If not specified, the payment is not session-bound.
-  :query timeout_ms=NUMBER: *Optional.*  If specified, the merchant backend 
will
-    wait up to ``timeout_ms`` milliseconds for completion of the payment before
-    sending the HTTP response.  A client must never rely on this behavior, as 
the
-    merchant backend may return a response immediately.
-  :query refund=AMOUNT: *Optional*. Indicates that we are polling for a refund 
above the given AMOUNT. Only useful in combination with timeout.
-  :query await_refund_obtained=BOOLEAN: *Optional*. If set to "yes", poll for 
the order's pending refunds to be picked up.
-
-  **Response:**
-
-  :status 200 OK:
-    The response is a `StatusPaidResponse`.
-  :status 202 Accepted:
-    The response is a `StatusGotoResponse`. Only returned if the content type 
requested was not HTML.
-  :status 302 Found:
-    The client should go to the indicated location. Only returned if the 
content type requested was HTML.
-  :status 402 PaymentRequired:
-    The response is a `StatusUnpaidResponse`.
-  :status 403 Forbidden:
-    The ``h_contract`` (or the ``token`` for unclaimed orders) does not match 
the order
-    and we have no fulfillment URL in the contract.
-  :status 410 Gone:
-    The response is a `StatusGoneResponse`.
-  :status 404 Not found:
-    The merchant backend is unaware of the order.
-  :status 406 Not Acceptable:
-    The merchant backend could not load the template required to generate a 
reply in the desired format. (Likely HTML templates were not properly 
installed.)
-
-  .. ts:def:: StatusPaidResponse
+Some orders may contain sensitive information that the merchant may not want
+to retain after fulfillment, such as the customer's shipping address.  By
+initially labeling these order components as forgettable, the merchant can
+later tell the backend to forget those details (without changing the hash of
+the contract!) to minimize risks from information leakage.
 
-    interface StatusPaid {
-      // Was the payment refunded (even partially, via refund or abort)?
-      refunded: boolean;
 
-      // Is any amount of the refund still waiting to be picked up (even 
partially)
-      refund_pending: boolean;
+.. http:patch:: /private/orders/$ORDER_ID/forget
 
-      // Amount that was refunded in total.
-      refund_amount: Amount;
-    }
+  Forget fields in an order's contract terms that the merchant no
+  longer needs.
 
-    .. ts:def:: StatusGotoResponse
+  **Request:**
 
-    interface StatusGotoResponse {
-      // The client should go to the fulfillment URL, it may be ready or
-      // might have some other interesting status.
-      fulfillment_url: string;
-    }
+  The request must be a `forget request <ForgetRequest>`. The fields specified
+  must have been marked as forgettable when the contract was created. Fields in
+  the request that are not in the `contract terms <ContractTerms>` are ignored.
 
-  .. ts:def:: StatusUnpaidResponse
+  A valid
+  JSON path is defined as a string beginning with ``$.`` that follows the dot
+  notation: ``$.wire_fee``, for example. The ``$`` represents the `contract 
terms <ContractTerms>`
+  object, and an identifier following a ``.`` represents the field of that
+  identifier belonging to the object preceding the dot. Arrays can be indexed
+  by an non-negative integer within brackets: ``$.products[1]``. An asterisk 
``*``
+  can be used to index an array as a wildcard, which expands the path into a
+  list of paths containing one path for
+  each valid array index: ``$.products[*].description``. For a path to be 
valid,
+  it must end with a reference to a field of an object (it cannot end with an
+  array index or wildcard).
 
-    interface StatusUnpaidResponse {
-      // URI that the wallet must process to complete the payment.
-      taler_pay_uri: string;
+  **Response:**
 
-      // Status URL, can be used as a redirect target for the browser
-      // to show the order QR code / trigger the wallet.
-      fulfillment_url?: string;
+  :status 200 OK:
+    The merchant deleted the specified fields from the contract of
+    order $ORDER_ID.
+  :status 400 Bad request:
+    The request is malformed or one of the paths is invalid.
+  :status 404 Not found:
+    The merchant backend could not find the order or the instance
+    and thus cannot process the abort request.
+  :status 409 Conflict:
+    The request includes a field that was not marked as forgettable, so
+    the merchant cannot delete that field.
 
-      // Alternative order ID which was paid for already in the same session.
-      // Only given if the same product was purchased before in the same 
session.
-      already_paid_order_id?: string;
-    }
+  .. ts:def:: ForgetRequest
 
-  .. ts:def:: StatusGoneResponse
+    interface ForgetRequest {
 
-    // The client tried to access the order via the claim
-    // token (and not a valid h_contract), but the order can't be claimed
-    // anymore, as it is already paid.
-    interface StatusGoneResponse {
-      // Fulfillment URL for the order.
-      fulfillment_url: string;
+      // Array of valid JSON paths to forgettable fields in the order's
+      // contract terms.
+      fields: string[];
     }
 
 
@@ -1572,119 +1889,18 @@ Giving Refunds
     }
 
 
-.. http:post:: /orders/$ORDER_ID/refund
-
-  Obtain refunds for an order. After talking to the exchange, the refunds will
-  no longer be pending if processed successfully.
-
-  **Request:**
-
-  The request body is a `WalletRefundRequest` object.
-
-  **Response:**
-
-  :status 200 OK:
-    The response is a `WalletRefundResponse`.
-  :status 204 No content:
-    There are no refunds for the order.
-  :status 403 Forbidden:
-    The ``h_contract`` does not match the order.
-  :status 404 Not found:
-    The merchant backend is unaware of the order.
-
-  .. ts:def:: WalletRefundRequest
-
-    interface WalletRefundRequest {
-      // hash of the order's contract terms (this is used to authenticate the
-      // wallet/customer).
-      h_contract: HashCode;
-    }
-
-  .. ts:def:: WalletRefundResponse
-
-    interface WalletRefundResponse {
-      // Amount that was refunded in total.
-      refund_amount: Amount;
-
-      // Successful refunds for this payment, empty array for none.
-      refunds: MerchantCoinRefundStatus[];
-
-      // Public key of the merchant.
-      merchant_pub: EddsaPublicKey;
-
-    }
-
-  .. ts:def:: MerchantCoinRefundStatus
-
-    type MerchantCoinRefundStatus =
-      | MerchantCoinRefundSuccessStatus
-      | MerchantCoinRefundFailureStatus;
-
-  .. ts:def:: MerchantCoinRefundFailureStatus
-
-    // Details about why a refund failed.
-    interface MerchantCoinRefundFailureStatus {
-      // Used as tag for the sum type RefundStatus sum type.
-      type: "failure";
-
-      // HTTP status of the exchange request, must NOT be 200.
-      exchange_status: Integer;
-
-      // Taler error code from the exchange reply, if available.
-      exchange_code?: Integer;
-
-      // If available, HTTP reply from the exchange.
-      exchange_reply?: Object;
-
-      // Refund transaction ID.
-      rtransaction_id: Integer;
-
-      // public key of a coin that was refunded
-      coin_pub: EddsaPublicKey;
-
-      // Amount that was refunded, including refund fee charged by the exchange
-      // to the customer.
-      refund_amount: Amount;
-    }
-
-  .. ts:def:: MerchantCoinRefundSuccessStatus
-
-    // Additional details needed to verify the refund confirmation signature
-    // (``h_contract_terms`` and ``merchant_pub``) are already known
-    // to the wallet and thus not included.
-    interface MerchantCoinRefundSuccessStatus {
-      // Used as tag for the sum type MerchantCoinRefundStatus sum type.
-      type: "success";
-
-      // HTTP status of the exchange request, 200 (integer) required for 
refund confirmations.
-      exchange_status: 200;
-
-      // the EdDSA :ref:`signature` (binary-only) with purpose
-      // `TALER_SIGNATURE_EXCHANGE_CONFIRM_REFUND` using a current signing key 
of the
-      // exchange affirming the successful refund
-      exchange_sig: EddsaSignature;
-
-      // public EdDSA key of the exchange that was used to generate the 
signature.
-      // Should match one of the exchange's signing keys from /keys.  It is 
given
-      // explicitly as the client might otherwise be confused by clock skew as 
to
-      // which signing key was used.
-      exchange_pub: EddsaPublicKey;
-
-      // Refund transaction ID.
-      rtransaction_id: Integer;
-
-      // public key of a coin that was refunded
-      coin_pub: EddsaPublicKey;
+-----------------------
+Tracking Wire Transfers
+-----------------------
 
-      // Amount that was refunded, including refund fee charged by the exchange
-      // to the customer.
-      refund_amount: Amount;
-    }
+This API is used by merchants that want to track the payments from the
+exchange to be sure that they have been paid on time. By telling the merchant
+backend about all incoming wire transfers, the backend can detect if an
+exchange failed to perform a wire transfer that was due.
 
 
-------------------------
-Tracking Wire Transfers
-------------------------
+Informing the backend about incoming wire transfers
+---------------------------------------------------
 
 .. http:post:: /private/transfers
 
@@ -1822,7 +2038,7 @@ Tracking Wire Transfers
 
       // Master public key of the exchange
       master_pub: EddsaPublicKey;
-  }
+    }
 
 
   .. ts:def:: TrackTransferConflictDetails
@@ -1906,6 +2122,8 @@ Tracking Wire Transfers
     }
 
 
+Querying known wire transfers
+-----------------------------
 
 .. http:get:: /private/transfers
 
@@ -1980,12 +2198,32 @@ Tracking Wire Transfers
     }
 
 
-
-
 --------------------
-Giving Customer Tips
+Backend: Giving tips
 --------------------
 
+Tips are a way for websites to give small amounts of e-cash to visitors (for
+example as a financial reward for providing information or watching
+advertisements).  Tips are non-contractual: neither merchant nor consumer
+have any contractual information about the other party as a result of the
+tip.
+
+
+Create reserve
+--------------
+
+Reserves are basically funds a merchant has provided
+to an exchange for a tipping campaign. Each reserve
+has a limited lifetime (say 2--4 weeks). Any funds
+not used to tip customers will automatically be wired
+back from the exchange to the originating account.
+
+To begin tipping, a merchant must tell the backend
+to setup a reserve. The backend will return a
+reserve public key which must be used as the wire
+transfer subject when wiring the tipping campaign
+funds to the exchange.
+
 .. _tips:
 .. http:post:: /private/reserves
 
@@ -2088,6 +2326,9 @@ Giving Customer Tips
       active: boolean;
     }
 
+    
+Query funds remaining
+---------------------
 
 .. http:get:: /private/reserves/$RESERVE_PUB
 
@@ -2157,6 +2398,9 @@ Giving Customer Tips
     }
 
 
+Authorizing tips
+----------------
+
 .. http:post:: /private/reserves/$RESERVE_PUB/authorize-tip
 
   Authorize creation of a tip from the given reserve.
@@ -2228,6 +2472,9 @@ Giving Customer Tips
     in all of the reserves of the instance.
 
 
+Deleting reserves
+-----------------
+    
 .. http:delete:: /private/reserves/$RESERVE_PUB
 
   Delete information about a reserve.  Fails if the reserve still has
@@ -2250,6 +2497,8 @@ Giving Customer Tips
     The backend refuses to delete the reserve (committed tips awaiting pickup).
 
 
+Checking tip status
+-------------------
 
 .. http:get:: /private/tips/$TIP_ID
 
@@ -2303,46 +2552,6 @@ Giving Customer Tips
     }
 
 
-
-.. http:get:: /tips/$TIP_ID
-
-  Handle request from wallet to provide details about a tip.
-
-  This endpoint typically also supports requests with the "Accept" header
-  requesting "text/html".  In this case, an HTML response suitable for
-  triggering the interaction with the wallet is returned. If the backend
-  installation does not include the required HTML templates, a 406 status
-  code is returned.
-
-  **Response:**
-
-  :status 200 OK:
-    A tip is being returned. The backend responds with a `TipInformation`.
-  :status 404 Not Found:
-    The tip identifier is unknown.
-  :status 406 Not Acceptable:
-    The merchant backend could not load the template required to generate a 
reply in the desired format. (Likely HTML templates were not properly 
installed.)
-  :status 410 Gone:
-    A tip has been fully claimed. The JSON reply still contains the 
`TipInformation`.
-
-  .. ts:def:: TipInformation
-
-    interface TipInformation {
-
-      // Exchange from which the tip will be withdrawn. Needed by the
-      // wallet to determine denominations, fees, etc.
-      exchange_url: string;
-
-      // (remaining) amount of the tip (including fees).
-      tip_amount: Amount;
-
-      // Timestamp indicating when the tip is set to expire (may be in the 
past).
-      // Note that tips that have expired MAY also result in a 404 response.
-      expiration: Timestamp;
-    }
-
-
-
 .. http:get:: /private/tips
 
   Return the list of all tips.
@@ -2385,68 +2594,17 @@ Giving Customer Tips
 
 
 
-.. http:post:: /tips/$TIP_ID/pickup
-
-  Handle request from wallet to pick up a tip.
-
-  **Request:**
-
-  The request body is a `TipPickupRequest` object.
-
-  **Response:**
-
-  :status 200 OK:
-    A tip is being returned. The backend responds with a `TipResponse`
-  :status 401 Unauthorized:
-    The tip amount requested exceeds the tip.
-  :status 404 Not Found:
-    The tip identifier is unknown.
-  :status 409 Conflict:
-    Some of the denomination key hashes of the request do not match those 
currently available from the exchange (hence there is a conflict between what 
the wallet requests and what the merchant believes the exchange can provide).
-  :status 410 Gone:
-    The tip has expired.
-
-  .. ts:def:: TipPickupRequest
-
-    interface TipPickupRequest {
-
-      // List of planches the wallet wants to use for the tip
-      planchets: PlanchetDetail[];
-    }
-
-  .. ts:def:: PlanchetDetail
-
-    interface PlanchetDetail {
-      // Hash of the denomination's public key (hashed to reduce
-      // bandwidth consumption)
-      denom_pub_hash: HashCode;
-
-      // coin's blinded public key
-      coin_ev: CoinEnvelope;
-    }
-
-  .. ts:def:: TipResponse
-
-    interface TipResponse {
-
-      // Blind RSA signatures over the planchets.
-      // The order of the signatures matches the planchets list.
-      blind_sigs: BlindSignature[];
-    }
-
-  .. ts:def:: BlindSignature
-
-    interface BlindSignature {
-
-      // The (blind) RSA signature. Still needs to be unblinded.
-      blind_sig: BlindedRsaSignature;
-    }
-
-
 ------------------
 The Contract Terms
 ------------------
 
+This section describes the overall structure of
+the contract terms that are the foundation for
+Taler payments.
+
+FIXME: the "forgettable" attribute is not
+properly specified here!
+
 .. _contract-terms:
 
 The contract terms must have the following structure:
diff --git a/taler-merchant-manual.rst b/taler-merchant-manual.rst
index 1e6e72a..d93c12d 100644
--- a/taler-merchant-manual.rst
+++ b/taler-merchant-manual.rst
@@ -1278,6 +1278,8 @@ FIXME: which coin denominations are needed for the 
benchmark?
 
 FIXME: provide "minimum" configuration file!
 
+DOCUMENT how to run taler-merchant-benchmark: configuration MUST set exchange 
bank password to 'x'!
+
 FIXME: explain Postgres setup!
 
 
@@ -1357,10 +1359,6 @@ interesting, there are:
 -  ``--unaggregated-number=UN`` This option instructs the tool to
    perform *UN* (one coin) payments that will be left unaggregated.
 
--  ``--alt-instance=AI`` This option instructs the tool to perform
-   payments using the merchant instance *AI* (instead of the *default*
-   instance)
-
 As for the ``ordinary`` subcommand, it is worth explaining the following
 options:
 

-- 
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]