commit 836cfb2029b0a3ce08102e95757ef06ed2cdc25e
parent e770c5147e7ac07b106567b31218d44741bcab66
Author: Christian Grothoff <christian@grothoff.org>
Date: Sun, 24 May 2026 22:47:10 +0200
try to de-duplicate and clean up (and precise) contract terms/orders/template specification
Diffstat:
4 files changed, 543 insertions(+), 570 deletions(-)
diff --git a/core/api-merchant.rst b/core/api-merchant.rst
@@ -317,7 +317,6 @@ Querying payment status
.. include:: merchant/get-orders-ORDER_ID.rst
-
.. include:: merchant/get-sessions-SESSION_ID.rst
@@ -361,7 +360,6 @@ 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.
-
.. include:: merchant/post-orders-ORDER_ID-refund.rst
@@ -379,10 +377,8 @@ Setting up instances
.. include:: merchant/post-instances.rst
-
.. include:: merchant/post-instances-INSTANCE-forgot-password.rst
-
.. include:: merchant/post-management-instances.rst
.. include:: merchant/post-management-instances-INSTANCE-auth.rst
@@ -442,7 +438,6 @@ One or more bank accounts must be associated with an instance
so that the instance can receive payments. Payments may be made
into any of the active bank accounts of an instance.
-
.. include:: merchant/post-private-accounts.rst
.. include:: merchant/patch-private-accounts-H_WIRE.rst
@@ -489,13 +484,10 @@ Managing measurement units
.. include:: merchant/get-private-units-UNIT.rst
-
.. include:: merchant/post-private-units.rst
-
.. include:: merchant/patch-private-units-UNIT.rst
-
.. include:: merchant/delete-private-units-UNIT.rst
@@ -506,10 +498,8 @@ Managing product categories
.. include:: merchant/get-private-categories-CATEGORY_ID.rst
-
.. include:: merchant/post-private-categories.rst
-
.. include:: merchant/patch-private-categories-CATEGORY_ID.rst
.. include:: merchant/delete-private-categories-CATEGORY_ID.rst
@@ -520,16 +510,12 @@ Managing products in the inventory
.. include:: merchant/post-private-products.rst
-
.. include:: merchant/patch-private-products-PRODUCT_ID.rst
-
.. include:: merchant/get-private-products.rst
-
.. include:: merchant/get-private-products-PRODUCT_ID.rst
-
.. include:: merchant/delete-private-products-PRODUCT_ID.rst
@@ -553,7 +539,6 @@ Reserving inventory
.. include:: merchant/post-private-products-PRODUCT_ID-lock.rst
-
------------------
Payment processing
------------------
@@ -579,7 +564,6 @@ Inspecting orders
.. include:: merchant/get-private-orders-ORDER_ID.rst
-
.. _private-order-data-cleanup:
Private order data cleanup
@@ -591,10 +575,8 @@ 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.
-
.. include:: merchant/patch-private-orders-ORDER_ID-forget.rst
-
.. include:: merchant/delete-private-orders-ORDER_ID.rst
@@ -727,7 +709,6 @@ SMS to their mobile phone. For points-of-sale without a mobile phone or
Internet connectivity, the OTP mechanism can also be used to confirm payments.
-
Adding templates
^^^^^^^^^^^^^^^^
@@ -932,7 +913,6 @@ Editing pots
.. include:: merchant/patch-private-pots-POT_ID.rst
-
Inspecting pots
^^^^^^^^^^^^^^^
@@ -947,7 +927,6 @@ Removing pots
.. include:: merchant/delete-private-pots-POT_ID.rst
-
----------------------------------------
Token Families: Subscriptions, Discounts
----------------------------------------
@@ -1017,79 +996,237 @@ Deleting a charity instance
.. include:: merchant/delete-private-donau-DONAU_SERIAL.rst
-
------------------
The Contract Terms
------------------
-This section describes the overall structure of
-the contract terms that are the foundation for
-Taler payments.
+This section describes the overall structure of templates, orders and contract
+terms that are the foundation for Taler payments.
-.. _contract-terms:
+.. _template-contract-details:
-The contract terms must have the following structure:
+Templates
+^^^^^^^^^
-.. ts:def:: ContractTerms
+The template contract is like the most raw form where many choices are still
+open or deferred.
- type ContractTerms = ProtoContractTerms & ContractTermsNonce;
-.. ts:def:: ContractTermsNonce
+ .. ts:def:: TemplateContractDetails
- interface ContractTermsNonce {
+ type TemplateContractDetails = (TemplateContractFixedOrder | TemplateContractInventoryCart | TemplateContractPaivana) & TemplateContractCommon;
- // Nonce generated by the wallet and echoed by the merchant
- // in this field when the order is claimed and converted
- // into a contract that is bound to a wallet.
- nonce: EddsaPublicKey;
- }
+ .. ts:def:: TemplateContractCommon
-.. ts:def:: ProtoContractTerms
+ interface TemplateContractCommon {
+ // Template type to apply. Defaults to "fixed-order" if omitted.
+ // Prescribes which interface has to be followed
+ // Since protocol **v25**.
+ template_type?: TemplateType;
- type ProtoContractTerms = (ContractTermsV1 | ContractTermsV0) & ContractTermsCommon;
+ // Human-readable summary for the template.
+ summary?: string;
+ // Required currency for payments to the template.
+ // This parameter is optional and should not be present
+ // if "amount" is given.
+ currency?: string;
-.. ts:def:: ContractTermsV1
+ // The time the customer need to pay before his order will be deleted.
+ // It is deleted if the customer did not pay and if the duration is over.
+ pay_duration?: RelativeTime;
- interface ContractTermsV1 {
- // Version 1 supports the ``choices`` array, see
- // https://docs.taler.net/design-documents/046-mumimo-contracts.html.
- // @since protocol **v21**
- version: 1;
+ // How long will customers have to access / read / pick-up
+ // the resource they are buying? Will turn into
+ // max_pickup_time in the contract. Optional, if not given
+ // the duration is forever.
+ // Since protocol **v29**.
+ max_pickup_duration?: RelativeTime;
- // List of contract choices that the customer can select from.
- // @since protocol **v21**
- choices: ContractChoice[];
+ // Minimum age buyer must have (in years). Default is 0.
+ minimum_age?: Integer;
- // Map of storing metadata and issue keys of
- // token families referenced in this contract.
- // @since protocol **v21**
- token_families: { [token_family_slug: string]: ContractTokenFamily };
- }
+ // Inventory-cart: request a tip during instantiation.
+ // Since protocol **v25**.
+ request_tip?: boolean;
+ }
-.. ts:def:: ContractTermsV0
+ .. ts:def:: TemplateType
- interface ContractTermsV0 {
- // Defaults to version 0.
- version?: 0;
+ enum TemplateType {
+ FIXED_ORDER = "fixed-order",
+ INVENTORY_CART = "inventory-cart",
+ PAIVANA = "paivana"
+ }
- // Total price for the transaction, including tip.
- // The exchange will subtract deposit fees from that amount
- // before transferring it to the merchant.
- amount: Amount;
+ .. ts:def:: TemplateContractFixedOrder
- // Optional tip amount. Must match the currency of ``amount``.
- // Since protocol **v25**.
- tip?: Amount;
+ interface TemplateContractFixedOrder {
- // Maximum total deposit fee accepted by the merchant for this contract.
- // Overrides defaults of the merchant instance.
- max_fee: Amount;
- }
+ // The price is imposed by the merchant and cannot be changed by the customer.
+ // This parameter is optional.
+ amount?: Amount;
-.. ts:def:: ContractTermsCommon
+ }
- interface ContractTermsCommon {
+ .. ts:def:: TemplateContractInventoryCart
+
+ interface TemplateContractInventoryCart {
+
+ // Inventory-cart: allow any inventory item to be selected.
+ // Since protocol **v25**.
+ selected_all?: boolean;
+
+ // Inventory-cart: only products in these categories are selectable.
+ // Since protocol **v25**.
+ selected_categories?: Integer[];
+
+ // Inventory-cart: only these products are selectable.
+ // Since protocol **v25**.
+ selected_products?: string[];
+
+ // Inventory-cart: require exactly one selection entry.
+ // Since protocol **v25**.
+ choose_one?: boolean;
+
+ // Inventory-cart: backend-provided payload with selectable data.
+ // Only present in ``GET /templates/$TEMPLATE_ID`` responses.
+ // Since protocol **v25**.
+ inventory_payload?: InventoryPayload;
+ }
+
+ .. ts:def:: TemplateContractPaivana
+
+ interface TemplateContractPaivana {
+
+ // Regular expression over URLs for which
+ // this template is valid.
+ // Optional, if not given all URLs are accepted.
+ // Since protocol **v25**.
+ website_regex?: string;
+
+ // Methods to pay for the contract.
+ choices: OrderChoice[];
+ }
+
+.. _template-choice:
+
+Template Choices
+^^^^^^^^^^^^^^^^
+
+ The `OrderChoice` object describes a possible choice within an order. The
+ choice is done by the wallet and consists of in- and outputs. In the example
+ of buying an article, the merchant could present the customer with the
+ choice to use a valid subscription token or pay using a gift
+ voucher. Available since protocol **v21**.
+
+ .. ts:def:: OrderChoice
+
+ interface OrderChoice {
+ // Total price for the choice. The exchange will subtract deposit
+ // fees from that amount before transferring it to the merchant.
+ amount: Amount;
+
+ // Optional tip amount. Must match the currency of ``amount``.
+ // Since protocol **v25**.
+ tip?: Amount;
+
+ // Human readable description of the semantics of the choice
+ // within the contract to be shown to the user at payment.
+ description?: string;
+
+ // Map from IETF 47 language tags to localized descriptions.
+ description_i18n?: { [lang_tag: string]: string };
+
+ // Inputs that must be provided by the customer, if this choice is selected.
+ // Defaults to empty array if not specified.
+ inputs?: OrderInput[];
+
+ // Outputs provided by the merchant, if this choice is selected.
+ // Defaults to empty array if not specified.
+ outputs?: OrderOutput[];
+
+ // Maximum total deposit fee accepted by the merchant for this contract.
+ // Overrides defaults of the merchant instance.
+ max_fee?: Amount;
+ }
+
+ .. ts:def:: OrderInput
+
+ // For now, only token inputs are supported.
+ type OrderInput = OrderInputToken;
+
+ .. ts:def:: OrderInputToken
+
+ interface OrderInputToken {
+
+ // Token input.
+ type: "token";
+
+ // Token family slug as configured in the merchant backend. Slug is unique
+ // across all configured tokens of a merchant.
+ token_family_slug: string;
+
+ // How many units of the input are required.
+ // Defaults to 1 if not specified. Output with count == 0 are ignored by
+ // the merchant backend.
+ count?: Integer;
+
+ }
+
+ .. ts:def:: OrderOutput
+
+ type OrderOutput = OrderOutputToken | OrderOutputTaxReceipt;
+
+ .. ts:def:: OrderOutputToken
+
+ interface OrderOutputToken {
+
+ // Token output.
+ type: "token";
+
+ // Token family slug as configured in the merchant backend. Slug is unique
+ // across all configured tokens of a merchant.
+ token_family_slug: string;
+
+ // How many units of the output are issued by the merchant.
+ // Defaults to 1 if not specified. Output with count == 0 are ignored by
+ // the merchant backend.
+ count?: Integer;
+
+ // When should the output token be valid. Can be specified if the
+ // desired validity period should be in the future (like selling
+ // a subscription for the next month). Optional. If not given,
+ // the validity is supposed to be "now" (time of order creation).
+ valid_at?: Timestamp;
+
+ }
+
+ .. ts:def:: OrderOutputTaxReceipt
+
+ interface OrderOutputTaxReceipt {
+
+ // Tax receipt output.
+ type: "tax-receipt";
+
+ // Donation amount. Useful if the donation is only for
+ // part of the total.
+ // Optional, if not given the purchase total amount is
+ // assumed to be the donation amount.
+ amount?: Amount;
+ }
+
+.. _contract-base-terms:
+
+Contract base terms
+^^^^^^^^^^^^^^^^^^^
+
+These are the basic terms that are shared terms between orders and contracts
+and basically present (or optional) all the time.
+
+.. ts:def:: ContractBaseTerms
+
+ interface ContractBaseTerms {
// Human-readable description of the whole purchase.
summary: string;
@@ -1141,45 +1278,6 @@ The contract terms must have the following structure:
// messages.
fulfillment_message_i18n?: { [lang_tag: string]: string };
- // List of products that are part of the purchase (see `ProductSold`).
- products: ProductSold[];
-
- // Time when this contract was generated.
- timestamp: Timestamp;
-
- // After this deadline has passed, no refunds will be accepted.
- refund_deadline: Timestamp;
-
- // After this deadline, the merchant won't accept payments for the contract.
- pay_deadline: Timestamp;
-
- // Transfer deadline for the exchange. Must be in the
- // deposit permissions of coins used to pay for this order.
- wire_transfer_deadline: Timestamp;
-
- // Merchant's public key used to sign this proposal; this information
- // is typically added by the backend. Note that this can be an ephemeral key.
- merchant_pub: EddsaPublicKey;
-
- // Base URL of the (public!) merchant backend API.
- // Must be an absolute URL that ends with a slash.
- merchant_base_url: string;
-
- // More info about the merchant, see below.
- merchant: Merchant;
-
- // The hash of the merchant instance's wire details.
- h_wire: HashCode;
-
- // Wire transfer method identifier for the wire method associated with ``h_wire``.
- // The wallet may only select exchanges via a matching auditor if the
- // exchange also supports this wire method.
- // The wire transfer fees must be added based on this wire transfer method.
- wire_method: string;
-
- // Exchanges that the merchant accepts even if it does not accept any auditors that audit them.
- exchanges: Exchange[];
-
// Delivery location for (all!) products.
delivery_location?: Location;
@@ -1232,99 +1330,147 @@ The contract terms must have the following structure:
// for digital goods where the customer has a finite window
// for downloading the resource(s).
max_pickup_time?: Timestamp;
+
}
-.. ts:def:: ContractChoice
+.. _order-details:
- interface ContractChoice {
- // Price to be paid for this choice. Could be 0.
- // The price is in addition to other instruments,
- // such as rations and tokens.
- // The exchange will subtract deposit fees from that amount
- // before transferring it to the merchant.
- amount: Amount;
+Orders
+^^^^^^
- // Optional tip amount. Must match the currency of ``amount``.
- // Since protocol **v25**.
- tip?: Amount;
+ The `Order` object represents the starting point for new `ContractTerms`.
+ After validating and sanatizing all inputs, the merchant backend will add
+ additional information to the order and create a new `ContractTerms` object
+ that will be stored in the database.
- // Human readable description of the semantics of the choice
- // within the contract to be shown to the user at payment.
- description?: string;
+ .. ts:def:: Order
- // Map from IETF 47 language tags to localized descriptions.
- description_i18n?: { [lang_tag: string]: string };
+ type Order = ContractBaseTerms & (OrderV0 | OrderV1) & OrderCommon;
- // List of inputs the wallet must provision (all of them) to
- // satisfy the conditions for the contract.
- inputs: ContractInput[];
+ .. ts:def:: OrderV0
- // List of outputs the merchant promises to yield (all of them)
- // once the contract is paid.
- outputs: ContractOutput[];
+ interface OrderV0 {
+ // Optional, defaults to 0 if not set.
+ version?: 0;
- // Maximum total deposit fee accepted by the merchant for this contract.
- max_fee: Amount;
- }
+ // Total price for the transaction, including tip. The exchange will
+ // subtract deposit fees from that amount before transferring it to
+ // the merchant.
+ amount: Amount;
-.. ts:def:: ContractInput
+ // Optional tip amount. Must match the currency of ``amount``.
+ // Since protocol **v25**.
+ tip?: Amount;
- // For now, only tokens are supported as inputs.
- type ContractInput = ContractInputToken;
+ // Maximum total deposit fee accepted by the merchant for this contract.
+ // Overrides defaults of the merchant instance.
+ max_fee?: Amount;
+ }
-.. ts:def:: ContractInputToken
+ .. ts:def:: OrderV1
- interface ContractInputToken {
- type: "token";
+ interface OrderV1 {
+ // Version 1 order support discounts and subscriptions.
+ // https://docs.taler.net/design-documents/046-mumimo-contracts.html
+ // @since protocol **v21**
+ version: 1;
- // Slug of the token family in the
- // ``token_families`` map on the order.
- token_family_slug: string;
+ // List of contract choices that the customer can select from.
+ // @since protocol **v21**
+ choices: OrderChoice[];
+ }
- // Number of tokens of this type required.
- // Defaults to one if the field is not provided.
- count?: Integer;
- };
-.. ts:def:: ContractOutput
+ .. ts:def:: OrderCommon
- // For now, only tokens are supported as outputs.
- type ContractOutput = ContractOutputToken | ContractOutputTaxReceipt;
+ interface OrderCommon {
-.. ts:def:: ContractOutputToken
+ // List of products that are part of the purchase.
+ products?: ProductEntry[];
- interface ContractOutputToken {
- type: "token";
+ // After this deadline has passed, no refunds will be accepted.
+ // Overrides deadline calculated from ``refund_delay`` in
+ // ``PostOrderRequest``.
+ // A value of "never" is not allowed.
+ refund_deadline?: Timestamp;
- // Slug of the token family in the
- // 'token_families' map on the top-level.
- token_family_slug: string;
+ // After this deadline, the merchant won't accept payments for the contract.
+ // Overrides deadline calculated from default pay delay configured in
+ // merchant backend.
+ // A value of "never" is not allowed.
+ pay_deadline?: Timestamp;
- // Number of tokens to be issued.
- // Defaults to one if the field is not provided.
- count?: Integer;
+ // Transfer deadline for the exchange. Must be in the deposit permissions
+ // of coins used to pay for this order.
+ // Overrides deadline calculated from default wire transfer delay
+ // configured in merchant backend. Must be after refund deadline.
+ // A value of "never" is not allowed.
+ wire_transfer_deadline?: Timestamp;
- // Index of the public key for this output token
- // in the `ContractTokenFamily` ``keys`` array.
- key_index: Integer;
+ }
- }
+.. _product-entry:
-.. ts:def:: ContractOutputTaxReceipt
+Product entries
+^^^^^^^^^^^^^^^
- interface ContractOutputTaxReceipt {
+ .. ts:def:: ProductEntry
- // Tax receipt output.
- type: "tax-receipt";
+ type ProductEntry = (ProductSold | MinimalInventoryProduct);
- // Array of base URLs of donation authorities that can be
- // used to issue the tax receipts. The client must select one.
- donau_urls: string[];
- // Total amount that will be on the tax receipt.
- amount: Amount;
+The following `MinimalInventoryProduct` can be provided if the parts of the
+order are inventory-based, that is if the `PostOrderRequest` uses
+``inventory_products``. For such products, which must be in the backend's
+inventory, the backend can automatically fill in the amount and other details
+about the product that are known to it from its ``products`` table. Note that
+the ``inventory_products`` will be appended to the list of ``products`` that
+the frontend already put into the ``order``. So if the frontend can sell
+additional non-inventory products together with ``inventory_products``. Note
+that the backend will NOT update the ``amount`` of the ``order``, so the
+frontend must already have calculated the total price --- including the
+``inventory_products``.
- }
+ .. ts:def:: MinimalInventoryProduct
+
+ // 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.
+ interface MinimalInventoryProduct {
+
+ // Which product is requested (here mandatory!).
+ product_id: string;
+
+ // Legacy integer quantity.
+ // Deprecated since **v25**;
+ // defaults to 1 if both ``quantity`` and ``unit_quantity`` are absent.
+ quantity?: Integer;
+
+ // Preferred quantity string using "<integer>[.<fraction>]" syntax.
+ // @since **v25**;
+ unit_quantity?: string
+
+ // Money pot to use for this product, overrides value from
+ // the inventory if given.
+ // Since **v25**.
+ product_money_pot?: Integer;
+
+ }
+
+Clients must supply either ``quantity`` or ``unit_quantity`` when referencing
+inventory products. If both are missing the backend assumes a quantity of
+one. ``unit_quantity`` follows the same decimal-string rules as
+``unit_total_stock``.
+
+
+.. _contract-token-family:
+
+Contract token family
+^^^^^^^^^^^^^^^^^^^^^
+
+The contract token family provides additional meta-data about
+input and output tokens associated with a particular choice of
+payment.
.. ts:def:: ContractTokenFamily
@@ -1424,9 +1570,200 @@ The contract terms must have the following structure:
};
-The wallet must select an exchange that either the merchant accepts directly by
-listing it in the exchanges array, or for which the merchant accepts an auditor
-that audits that exchange by listing it in the auditors array.
+.. _proto-contract-terms:
+
+Proto contract terms
+^^^^^^^^^^^^^^^^^^^^
+
+The proto-contract terms are the proposed contract that a merchant
+is about to present to a wallet, but that lacks the wallet's *nonce*
+and is thus not yet buyer-specific.
+
+
+
+.. ts:def:: ProtoContractTerms
+
+ type ProtoContractTerms = ContractBaseTerms & (ContractTermsV0 | ContractTermsV1) & ContractTermsCommon;
+
+
+.. ts:def:: ContractTermsV0
+
+ interface ContractTermsV0 {
+ // Defaults to version 0.
+ version?: 0;
+
+ // Total price for the transaction, including tip.
+ // The exchange will subtract deposit fees from that amount
+ // before transferring it to the merchant.
+ amount: Amount;
+
+ // Optional tip amount. Must match the currency of ``amount``.
+ // Since protocol **v25**.
+ tip?: Amount;
+
+ // Maximum total deposit fee accepted by the merchant for this contract.
+ // Overrides defaults of the merchant instance.
+ max_fee: Amount;
+ }
+
+.. ts:def:: ContractTermsV1
+
+ interface ContractTermsV1 {
+ // Version 1 supports the ``choices`` array, see
+ // https://docs.taler.net/design-documents/046-mumimo-contracts.html.
+ // @since protocol **v21**
+ version: 1;
+
+ // List of contract choices that the customer can select from.
+ // @since protocol **v21**
+ choices: ContractChoice[];
+
+ // Map of storing metadata and issue keys of
+ // token families referenced in this contract.
+ // @since protocol **v21**
+ token_families: { [token_family_slug: string]: ContractTokenFamily };
+ }
+
+.. ts:def:: ContractTermsCommon
+
+ interface ContractTermsCommon {
+
+ // Time when this contract was generated.
+ timestamp: Timestamp;
+
+ // After this deadline has passed, no refunds will be accepted.
+ refund_deadline: Timestamp;
+
+ // After this deadline, the merchant won't accept payments for the contract.
+ pay_deadline: Timestamp;
+
+ // Transfer deadline for the exchange. Must be in the
+ // deposit permissions of coins used to pay for this order.
+ wire_transfer_deadline: Timestamp;
+
+ // Merchant's public key used to sign this proposal; this information
+ // is typically added by the backend. Note that this can be an ephemeral key.
+ merchant_pub: EddsaPublicKey;
+
+ // Base URL of the (public!) merchant backend API.
+ // Must be an absolute URL that ends with a slash.
+ merchant_base_url: string;
+
+ // More info about the merchant, see below.
+ merchant: Merchant;
+
+ // List of products that are part of the purchase (see `ProductSold`).
+ products: ProductSold[];
+
+ // The hash of the merchant instance's wire details.
+ h_wire: HashCode;
+
+ // Wire transfer method identifier for the wire method associated with ``h_wire``.
+ // The wallet may only select exchanges via a matching auditor if the
+ // exchange also supports this wire method.
+ // The wire transfer fees must be added based on this wire transfer method.
+ wire_method: string;
+
+ // Exchanges that the merchant accepts even if it does not accept any auditors that audit them.
+ exchanges: Exchange[];
+
+ }
+
+.. ts:def:: ContractChoice
+
+ interface ContractChoice {
+ // Price to be paid for this choice. Could be 0.
+ // The price is in addition to other instruments,
+ // such as rations and tokens.
+ // The exchange will subtract deposit fees from that amount
+ // before transferring it to the merchant.
+ amount: Amount;
+
+ // Optional tip amount. Must match the currency of ``amount``.
+ // Since protocol **v25**.
+ tip?: Amount;
+
+ // Human readable description of the semantics of the choice
+ // within the contract to be shown to the user at payment.
+ description?: string;
+
+ // Map from IETF 47 language tags to localized descriptions.
+ description_i18n?: { [lang_tag: string]: string };
+
+ // List of inputs the wallet must provision (all of them) to
+ // satisfy the conditions for the contract.
+ inputs: ContractInput[];
+
+ // List of outputs the merchant promises to yield (all of them)
+ // once the contract is paid.
+ outputs: ContractOutput[];
+
+ // Maximum total deposit fee accepted by the merchant for this contract.
+ max_fee: Amount;
+ }
+
+.. ts:def:: ContractInput
+
+ // For now, only tokens are supported as inputs.
+ type ContractInput = ContractInputToken;
+
+.. ts:def:: ContractInputToken
+
+ interface ContractInputToken {
+ type: "token";
+
+ // Slug of the token family in the
+ // ``token_families`` map on the order.
+ token_family_slug: string;
+
+ // Number of tokens of this type required.
+ // Defaults to one if the field is not provided.
+ count?: Integer;
+ };
+
+.. ts:def:: ContractOutput
+
+ // For now, only tokens are supported as outputs.
+ type ContractOutput = ContractOutputToken | ContractOutputTaxReceipt;
+
+.. ts:def:: ContractOutputToken
+
+ interface ContractOutputToken {
+ type: "token";
+
+ // Slug of the token family in the
+ // 'token_families' map on the top-level.
+ token_family_slug: string;
+
+ // Number of tokens to be issued.
+ // Defaults to one if the field is not provided.
+ count?: Integer;
+
+ // Index of the public key for this output token
+ // in the `ContractTokenFamily` ``keys`` array.
+ key_index: Integer;
+
+ }
+
+.. ts:def:: ContractOutputTaxReceipt
+
+ interface ContractOutputTaxReceipt {
+
+ // Tax receipt output.
+ type: "tax-receipt";
+
+ // Array of base URLs of donation authorities that can be
+ // used to issue the tax receipts. The client must select one.
+ donau_urls: string[];
+
+ // Total amount that will be on the tax receipt.
+ amount: Amount;
+
+ }
+
+
+Product listing
+^^^^^^^^^^^^^^^
The `ProductSold` object describes a product and the quantity
being purchased from the merchant as well as possibly the price
@@ -1573,18 +1910,12 @@ It has the following structure:
address_lines?: string[];
}
-.. ts:def:: Auditor
- interface Auditor {
- // Official name.
- name: string;
+Exchanges
+^^^^^^^^^
- // Auditor's public key.
- auditor_pub: EddsaPublicKey;
-
- // Base URL of the auditor.
- url: string;
- }
+The wallet must select an exchange that either the merchant accepts by
+listing it in the exchanges array.
.. ts:def:: Exchange
@@ -1619,3 +1950,26 @@ each object (from ``ContractTerms`` down)
can mark certain fields as "forgettable" by listing the names of those fields
in a special peer field ``_forgettable``.
(See :ref:`Private order data cleanup <private-order-data-cleanup>`.)
+
+
+.. _contract-terms:
+
+Final contract terms
+^^^^^^^^^^^^^^^^^^^^
+
+The contract terms are the final object that is signed by both
+parties to finalize a purchase. It must have the following structure:
+
+.. ts:def:: ContractTerms
+
+ type ContractTerms = ProtoContractTerms & ContractTermsNonce;
+
+.. ts:def:: ContractTermsNonce
+
+ interface ContractTermsNonce {
+
+ // Nonce generated by the wallet and echoed by the merchant
+ // in this field when the order is claimed and converted
+ // into a contract that is bound to a wallet.
+ nonce: EddsaPublicKey;
+ }
diff --git a/core/merchant/post-orders-ORDER_ID-claim.rst b/core/merchant/post-orders-ORDER_ID-claim.rst
@@ -48,7 +48,7 @@
.. ts:def:: ClaimResponse
interface ClaimResponse {
- // Contract terms of the claimed order
+ // Contract terms of the claimed order.
contract_terms: ContractTerms;
// Signature by the merchant over the contract terms.
diff --git a/core/merchant/post-private-orders.rst b/core/merchant/post-private-orders.rst
@@ -149,289 +149,6 @@
}
- The `Order` object represents the starting point for new `ContractTerms`.
- After validating and sanatizing all inputs, the merchant backend will add
- additional information to the order and create a new `ContractTerms` object
- that will be stored in the database.
-
- .. ts:def:: Order
-
- type Order = (OrderV1 | OrderV0) & OrderCommon;
-
- .. ts:def:: OrderV1
-
- interface OrderV1 {
- // Version 1 order support discounts and subscriptions.
- // https://docs.taler.net/design-documents/046-mumimo-contracts.html
- // @since protocol **v21**
- version: 1;
-
- // List of contract choices that the customer can select from.
- // @since protocol **v21**
- choices?: OrderChoice[];
- }
-
- .. ts:def:: OrderV0
-
- interface OrderV0 {
- // Optional, defaults to 0 if not set.
- version?: 0;
-
- // Total price for the transaction, including tip. The exchange will
- // subtract deposit fees from that amount before transferring it to
- // the merchant.
- amount: Amount;
-
- // Optional tip amount. Must match the currency of ``amount``.
- // Since protocol **v25**.
- tip?: Amount;
-
- // Maximum total deposit fee accepted by the merchant for this contract.
- // Overrides defaults of the merchant instance.
- max_fee?: Amount;
- }
-
- .. ts:def:: OrderCommon
-
- interface OrderCommon {
- // Human-readable description of the whole purchase.
- summary: string;
-
- // Map from IETF BCP 47 language tags to localized summaries.
- summary_i18n?: { [lang_tag: string]: string };
-
- // Unique identifier for the order. Only characters
- // allowed are "A-Za-z0-9" and ".:_-".
- // Must be unique within a merchant instance.
- // For merchants that do not store proposals in their DB
- // before the customer paid for them, the ``order_id`` can be used
- // by the frontend to restore a proposal from the information
- // encoded in it (such as a short product identifier and timestamp).
- order_id?: string;
-
- // URL where the same contract could be ordered again (if
- // available). Returned also at the public order endpoint
- // for people other than the actual buyer (hence public,
- // in case order IDs are guessable).
- public_reorder_url?: string;
-
- // See documentation of ``fulfillment_url`` field in `ContractTerms`.
- // Either fulfillment_url or fulfillment_message must be specified.
- // When creating an order, the fulfillment URL can
- // contain ``${ORDER_ID}`` which will be substituted with the
- // order ID of the newly created order.
- fulfillment_url?: string;
-
- // See documentation of ``fulfillment_message`` in `ContractTerms`.
- // Either ``fulfillment_url`` or ``fulfillment_message`` must be specified.
- fulfillment_message?: string;
-
- // Map from IETF BCP 47 language tags to localized fulfillment
- // messages.
- fulfillment_message_i18n?: { [lang_tag: string]: string };
-
- // Minimum age the buyer must have to buy.
- minimum_age?: Integer;
-
- // List of products that are part of the purchase.
- products?: ProductSold[];
-
- // Time when this contract was generated. If null, defaults to current
- // time of merchant backend.
- timestamp?: Timestamp;
-
- // After this deadline has passed, no refunds will be accepted.
- // Overrides deadline calculated from ``refund_delay`` in
- // ``PostOrderRequest``.
- // A value of "never" is not allowed.
- refund_deadline?: Timestamp;
-
- // After this deadline, the merchant won't accept payments for the contract.
- // Overrides deadline calculated from default pay delay configured in
- // merchant backend.
- // A value of "never" is not allowed.
- pay_deadline?: Timestamp;
-
- // Transfer deadline for the exchange. Must be in the deposit permissions
- // of coins used to pay for this order.
- // Overrides deadline calculated from default wire transfer delay
- // configured in merchant backend. Must be after refund deadline.
- // A value of "never" is not allowed.
- wire_transfer_deadline?: Timestamp;
-
- // Base URL of the (public!) merchant backend API.
- // Must be an absolute URL that ends with a slash.
- // Defaults to the base URL this request was made to.
- merchant_base_url?: string;
-
- // Delivery location for (all!) products.
- delivery_location?: Location;
-
- // Time indicating when the order should be delivered.
- // May be overwritten by individual products.
- // Must be in the future.
- delivery_date?: Timestamp;
-
- // See documentation of ``auto_refund`` in ``ContractTerms``.
- // Specifies for how long the wallet should try to get an
- // automatic refund for the purchase.
- auto_refund?: RelativeTime;
-
- // Extra data that is only interpreted by the merchant frontend.
- // Useful when the merchant needs to store extra information on a
- // contract without storing it separately in their database.
- // Must really be an Object (not a string, integer, float or array).
- extra?: Object;
-
- // Money pot to increment for whatever order payment amount
- // is not yet assigned to a pot via the ``ProductSold``.
- // Not useful to wallets, only for
- // merchant-internal accounting.
- // Since protocol **v25**.
- order_default_money_pot?: Integer;
-
- }
-
-
- The `OrderChoice` object describes a possible choice within an order. The
- choice is done by the wallet and consists of in- and outputs. In the example
- of buying an article, the merchant could present the customer with the
- choice to use a valid subscription token or pay using a gift
- voucher. Available since protocol **v21**.
-
- .. ts:def:: OrderChoice
-
- interface OrderChoice {
- // Total price for the choice. The exchange will subtract deposit
- // fees from that amount before transferring it to the merchant.
- amount: Amount;
-
- // Optional tip amount. Must match the currency of ``amount``.
- // Since protocol **v25**.
- tip?: Amount;
-
- // Human readable description of the semantics of the choice
- // within the contract to be shown to the user at payment.
- description?: string;
-
- // Map from IETF 47 language tags to localized descriptions.
- description_i18n?: { [lang_tag: string]: string };
-
- // Inputs that must be provided by the customer, if this choice is selected.
- // Defaults to empty array if not specified.
- inputs?: OrderInput[];
-
- // Outputs provided by the merchant, if this choice is selected.
- // Defaults to empty array if not specified.
- outputs?: OrderOutput[];
-
- // Maximum total deposit fee accepted by the merchant for this contract.
- // Overrides defaults of the merchant instance.
- max_fee?: Amount;
- }
-
- .. ts:def:: OrderInput
-
- // For now, only token inputs are supported.
- type OrderInput = OrderInputToken;
-
- .. ts:def:: OrderInputToken
-
- interface OrderInputToken {
-
- // Token input.
- type: "token";
-
- // Token family slug as configured in the merchant backend. Slug is unique
- // across all configured tokens of a merchant.
- token_family_slug: string;
-
- // How many units of the input are required.
- // Defaults to 1 if not specified. Output with count == 0 are ignored by
- // the merchant backend.
- count?: Integer;
-
- }
-
- .. ts:def:: OrderOutput
-
- type OrderOutput = OrderOutputToken | OrderOutputTaxReceipt;
-
- .. ts:def:: OrderOutputToken
-
- interface OrderOutputToken {
-
- // Token output.
- type: "token";
-
- // Token family slug as configured in the merchant backend. Slug is unique
- // across all configured tokens of a merchant.
- token_family_slug: string;
-
- // How many units of the output are issued by the merchant.
- // Defaults to 1 if not specified. Output with count == 0 are ignored by
- // the merchant backend.
- count?: Integer;
-
- // When should the output token be valid. Can be specified if the
- // desired validity period should be in the future (like selling
- // a subscription for the next month). Optional. If not given,
- // the validity is supposed to be "now" (time of order creation).
- valid_at?: Timestamp;
-
- }
-
- .. ts:def:: OrderOutputTaxReceipt
-
- interface OrderOutputTaxReceipt {
-
- // Tax receipt output.
- type: "tax-receipt";
-
- }
-
- The following `MinimalInventoryProduct` can be provided if the parts of the
- order are inventory-based, that is if the `PostOrderRequest` uses
- ``inventory_products``. For such products, which must be in the backend's inventory,
- the backend can automatically fill in the amount and other details about
- the product that are known to it from its ``products`` table.
- Note that the ``inventory_products`` will be appended to the
- list of ``products`` that the frontend already put into the ``order``.
- So if the frontend can sell additional non-inventory products together
- with ``inventory_products``. Note that the backend will NOT update
- the ``amount`` of the ``order``, so the frontend must already have calculated
- the total price --- including the ``inventory_products``.
-
- .. ts:def:: MinimalInventoryProduct
-
- // 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.
- interface MinimalInventoryProduct {
-
- // Which product is requested (here mandatory!).
- product_id: string;
-
- // Legacy integer quantity.
- // Deprecated since **v25**;
- // defaults to 1 if both ``quantity`` and ``unit_quantity`` are absent.
- quantity?: Integer;
-
- // Preferred quantity string using "<integer>[.<fraction>]" syntax.
- // @since **v25**;
- unit_quantity?: string
-
- // Money pot to use for this product, overrides value from
- // the inventory if given.
- // Since **v25**.
- product_money_pot?: Integer;
-
- }
-
- Supply either ``quantity`` or ``unit_quantity`` when referencing inventory products. If both are
- missing the backend assumes a quantity of one. ``unit_quantity`` follows the same decimal-string
- rules as ``unit_total_stock``.
-
.. ts:def:: PostOrderResponse
interface PostOrderResponse {
diff --git a/core/merchant/post-private-templates.rst b/core/merchant/post-private-templates.rst
@@ -6,7 +6,7 @@
**Request:**
- The request must be a `TemplateAddDetails`.
+ The request must be a `TemplateCreateRequest`.
**Response:**
@@ -34,9 +34,9 @@
**Details:**
- .. ts:def:: TemplateAddDetails
+ .. ts:def:: TemplateCreateRequest
- interface TemplateAddDetails {
+ interface TemplateCreateRequest {
// Template ID to use.
template_id: string;
@@ -58,101 +58,3 @@
// Since protocol **v13**.
editable_defaults?: Object;
}
-
-
- .. ts:def:: TemplateContractDetails
-
- type TemplateContractDetails = (TemplateContractFixedOrder | TemplateContractInventoryCart | TemplateContractPaivana) & TemplateContractCommon;
-
- .. ts:def:: TemplateContractCommon
-
- interface TemplateContractCommon {
- // Template type to apply. Defaults to "fixed-order" if omitted.
- // Prescribes which interface has to be followed
- // Since protocol **v25**.
- template_type?: TemplateType;
-
- // Human-readable summary for the template.
- summary?: string;
-
- // Required currency for payments to the template.
- // This parameter is optional and should not be present
- // if "amount" is given.
- currency?: string;
-
- // The time the customer need to pay before his order will be deleted.
- // It is deleted if the customer did not pay and if the duration is over.
- pay_duration?: RelativeTime;
-
- // How long will customers have to access / read / pick-up
- // the resource they are buying? Will turn into
- // max_pickup_time in the contract. Optional, if not given
- // the duration is forever.
- // Since protocol **v29**.
- max_pickup_duration?: RelativeTime;
-
- // Minimum age buyer must have (in years). Default is 0.
- minimum_age?: Integer;
-
- // Inventory-cart: request a tip during instantiation.
- // Since protocol **v25**.
- request_tip?: boolean;
- }
-
- .. ts:def:: TemplateType
-
- enum TemplateType {
- FIXED_ORDER = "fixed-order",
- INVENTORY_CART = "inventory-cart",
- PAIVANA = "paivana"
- }
-
- .. ts:def:: TemplateContractFixedOrder
-
- interface TemplateContractFixedOrder {
-
- // The price is imposed by the merchant and cannot be changed by the customer.
- // This parameter is optional.
- amount?: Amount;
-
- }
-
- .. ts:def:: TemplateContractInventoryCart
-
- interface TemplateContractInventoryCart {
-
- // Inventory-cart: allow any inventory item to be selected.
- // Since protocol **v25**.
- selected_all?: boolean;
-
- // Inventory-cart: only products in these categories are selectable.
- // Since protocol **v25**.
- selected_categories?: Integer[];
-
- // Inventory-cart: only these products are selectable.
- // Since protocol **v25**.
- selected_products?: string[];
-
- // Inventory-cart: require exactly one selection entry.
- // Since protocol **v25**.
- choose_one?: boolean;
-
- // Inventory-cart: backend-provided payload with selectable data.
- // Only present in ``GET /templates/$TEMPLATE_ID`` responses.
- // Since protocol **v25**.
- inventory_payload?: InventoryPayload;
- }
-
- .. ts:def:: TemplateContractPaivana
-
- interface TemplateContractPaivana {
-
- // Regular expression over URLs for which
- // this template is valid.
- // Optional, if not given all URLs are accepted.
- // Since protocol **v25**.
- website_regex?: string;
-
- // Methods to pay for the contract.
- choices: OrderChoice[];
- }