taler-docs

Documentation for GNU Taler components, APIs and protocols
Log | Files | Refs | README | LICENSE

commit 06c8e0ef25c267c8eb77c40ac0d9ab9b07ad3e04
parent 67f02313f8acfaf18e7eb2790ed62bd93aa83053
Author: Stefan Kügel <stefan.kuegel@taler.net>
Date:   Thu, 30 Oct 2025 22:58:44 +0100

Merge branch 'master' of git+ssh://git.gnunet.org/taler-docs

Diffstat:
Mchecklists/checklist-release.rst | 37+++++++++++++++++++++++++++++++++++++
Mcore/api-exchange.rst | 6+++++-
Mcore/api-merchant.rst | 356+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------
Adesign-documents/071-auto-refresh.rst | 138+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adesign-documents/072-products-units.rst | 378+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mdesign-documents/index.rst | 2++
Mfrags/list-of-dependencies.rst | 2+-
Mmanpages/taler-merchant-passwd.1.rst | 9+++++++--
Mmanpages/taler-merchant.conf.5.rst | 45+++++++++++++++++++++++++++++++++++++++++++++
Mtaler-merchant-manual.rst | 115++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----
10 files changed, 998 insertions(+), 90 deletions(-)

diff --git a/checklists/checklist-release.rst b/checklists/checklist-release.rst @@ -5,6 +5,43 @@ GNU Taler Release Checklist <input type="checkbox"> + +Released components (repositories, dependency toposorted): + +- |releasecheck| taler-typescript-core.git +- |releasecheck| taler-twister.git +- |releasecheck| libeufin.git +- |releasecheck| challenger.git +- |releasecheck| exchange.git +- |releasecheck| donau.git +- |releasecheck| merchant.git +- |releasecheck| taler-mdb.git +- |releasecheck| sync.git +- taler-ios.git (no source release) +- taler-android.git (no source release) +- taler-merchant-demos.git (no source release) + + +Overall release process: + +- |releasecheck| Tag candidate tag of components that passed local checks (``x.y.z-dev.n``) +- (future) Run local CI for each package +- (future) Run build and integration test harness in sandcastle-ng +- |releasecheck| Bump version of components (via ``contrib/bump``) +- |releasecheck| Tag release of components that passed local checks (``x.y.z``) +- |releasecheck| Deploy on ``test.taler.net`` +- |releasecheck| Test ``test.taler.net`` +- |releasecheck| Deploy on ``demo.taler.net`` +- |releasecheck| Test ``demo.taler.net`` +- |releasecheck| Build Debian staging packages (via ``packaging-ng``) +- |releasecheck| Deploy in staging environments (``rusty`` etc.) +- |releasecheck| Test staging environments (``rusty`` etc.) +- |releasecheck| Promote Debian packages (via ``packaging-ng``) +- |releasecheck| Upload to GNU mirrors +- |releasecheck| Announce release +- |releasecheck| Deploy in production environments + + For exchange: - |releasecheck| no compiler warnings at "-Wall" with gcc diff --git a/core/api-exchange.rst b/core/api-exchange.rst @@ -1758,13 +1758,17 @@ exchange. that the client can commit to in a call to ``/withdraw``, this time with ``max_age`` set accordingly and ``coin_evs`` being an array of ``n*kappa`` elements of type `CoinEnvelope`. - 3. the provided value for ``max_age`` is higher than the allowed value + 3. The provided value for ``max_age`` is higher than the allowed value according to the reserve's birthday. The response comes with a standard `ErrorDetail` response with error-code ``TALER_EC_EXCHANGE_AGE_WITHDRAW_MAXIMUM_AGE_TOO_LARGE`` and an additional field ``maximum_allowed_age`` for the maximum age (in years) that the client can commit to in a call to ``/withdraw``. + 4. The request uses a nonce value that was previously seen by + the exchange for a different request. As nonces must be unique, + the request is rejected. This can only happen with some cipher + types that use nonces. :http:statuscode:`410 Gone`: A requested denomination key is no longer valid. There are two cases: diff --git a/core/api-merchant.rst b/core/api-merchant.rst @@ -125,7 +125,7 @@ of that instance. Currently, the ``/private/auth/`` API supports two main authentication methods in the ``InstanceAuthConfigurationMessage``: -* ``external``: (*@deprecated since v20*) With this method, no checks are done by the merchant backend. +* ``external``: (@deprecated since **v20**) With this method, no checks are done by the merchant backend. Instead, a reverse proxy / API gateway must do all authentication/authorization checks. * ``token`` (**@since v19**): With this method, the client must provide an authorization header that contains a bearer token when accessing a protected endpoint in the form @@ -135,14 +135,14 @@ Currently, the ``/private/auth/`` API supports two main authentication methods i A login token is commonly only valid for a limited period of time and scoped to specific permissions. If the ``$INSTANCE_PASSWORD`` is lost, the administrator can set a password using the ``taler-merchant-passwd`` command-line tool. -* ``token`` (*@deprecated since v19*): With this method, the client must provide an authentication token in +* ``token`` (@deprecated since **v19**): With this method, the client must provide an authentication token in the format ``secret-token: $INSTANCE_PASSWORD``. The behaviour is then equivalent to the ``token`` method above. Any API may be accessed using the bearer authentication ``secret-token: $INSTANCE_PASSWORD``. Notice that this behaviour is deprecated and will be phased out in favor of login tokens. For testing, the service may be started with the configuration option ``DISABLED_AUTHENTICATION = YES`` -in section ``[merchant]`` (@since v20). +in section ``[merchant]`` (@since **v20**). Scopes ^^^^^^ @@ -172,7 +172,7 @@ such as the implemented version of the protocol and the currency used. .. http:get:: /config Return the protocol version and currency supported by this merchant backend. - This specification corresponds to ``current`` protocol being version **v21**. + This specification corresponds to ``current`` protocol being version **v23**. **Response:** @@ -217,7 +217,7 @@ such as the implemented version of the protocol and the currency used. currencies: { currency : CurrencySpecification}; // Array of exchanges trusted by the merchant. - // Since protocol **v6**. + // @since **v6**. exchanges: ExchangeConfigInfo[]; // Set when the merchant supports @@ -229,22 +229,83 @@ such as the implemented version of the protocol and the currency used. // extension and can thus issue donation receipts. // Should primarily be used to control the SPA's CRUD // functionality for Donau. - // Since protocol **v21** + // @since **v21** have_donau: boolean; // Tan channels that are required // to be confirmed for an instance to // be useable. - // Since protocol **v21** + // @since **v21** mandatory_tan_channels?: TanChannel[]; + // Space-separated list of enabled payment target types. + // Useful if the SPA should not show allow adding other + // types of bank accounts. "*" is used to represent no + // restriction. + // @since **v22** + payment_target_types: string; + + // Regular expression representing further restrictions + // on allowed payment targets. Any "payto://"-URI supplied + // for a bank account must match the given regular expression. + // For example, "payto://iban/CH.*" would restrict the system + // to only Swiss bank accounts. + // Optional, no restrictions are imposed if the field is + // absent. + // @since **v22** + // CAUTION: Likely to be removed/deprecated, + // as we'll want an array of restrictions with the + // same format as the exchange uses, as this allows + // proper i18n and spec/code reuse. + payment_target_regex? string; + + // Default payment delay for new instances. + // This is the default to use for new instances, see the instance value for + // the instance-specific default. + // @since **v22** + default_pay_delay: RelativeTime; + + // If the frontend does NOT specify a refund deadline, how long should + // refunds be allowed by default? + // This is the default to use for new instances, see the instance value for + // the instance-specific default. + // @since **v22** + default_refund_delay: RelativeTime; + + // Default wire transfer delay for new instances. + // This is the default to use for new instances, see the instance value for + // the instance-specific default. + // @since **v22** + default_wire_transfer_delay: RelativeTime; + + // Default interval to which wire deadlines computed by + // adding the wire_transfer_delay on top of the refund + // deadline should be rounded up to. + // @since **v23** + default_wire_transfer_rounding_interval: RoundingInterval; } + .. ts:def:: TanChannel + enum TanChannel { SMS = "sms", EMAIL = "email" } + .. ts:def:: RoundingInterval + + enum RoundingInterval { + NONE = "none", + SECOND = "second", + MINUTE = "minute", + HOUR = "hour", + DAY = "day", + WEEK = "week", + MONTH = "month", + QUARTER = "quarter", + YEAR = "year" + } + .. ts:def:: ExchangeConfigInfo interface ExchangeConfigInfo { @@ -1436,16 +1497,32 @@ Setting up instances // Can always be overridden by the frontend on a per-order basis. use_stefan: boolean; - // 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_delay: RelativeTime; + // Optional @since **v22** (before the setting was mandatory). + // If not provided, the global merchant default will be used. + default_pay_delay?: RelativeTime; + + // If the frontend does NOT specify a refund deadline, how long should + // refunds be allowed by default? Added on top of the + // payment deadline. + // @since **v22** + default_refund_delay?: RelativeTime; + // 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 on top of + // the refund deadline and afterwards subject to rounding + // via the ``default_wire_transfer_rounding_interval``. + // Optional @since **v22** (before the setting was mandatory). + // If not provided, the global merchant default will be used. + default_wire_transfer_delay?: RelativeTime; + + // How far should the wire deadline (if computed with the help of + // the ``default_wire_transfer_delay``) be rounded up to compute + // the ultimate wire deadline? + // @since **v22**, defaults to no rounding if not given. + default_wire_transfer_rounding_interval?: RoundingInterval; } .. http:post:: /management/instances/$INSTANCE/auth @@ -1477,7 +1554,7 @@ Setting up instances .. ts:def:: InstanceAuthConfigToken - // @since v19 + // @since **v19** interface InstanceAuthConfigToken { // The API is accessible through API tokens. // Tokens are retrieved from the /private/token @@ -1494,7 +1571,7 @@ Setting up instances .. ts:def:: InstanceAuthConfigTokenOLD - // @deprecated since v19 + // @deprecated since **v19** interface InstanceAuthConfigTokenOLD { // The API is accessible through API tokens. // Tokens are retrieved from the /private/token @@ -1508,7 +1585,7 @@ Setting up instances .. ts:def:: InstanceAuthConfigExternal - // @deprecated since v20 + // @deprecated since **v20** interface InstanceAuthConfigExternal { // The mechant backend does not do // any authentication checks. Instead an API @@ -1733,16 +1810,31 @@ Setting up instances // Can always be overridden by the frontend on a per-order basis. use_stefan: boolean; - // 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_delay: RelativeTime; + // Optional @since **v22** (before the setting was mandatory). + // If not provided, the previous setting will now simply be preserved. + default_pay_delay?: RelativeTime; + // If the frontend does NOT specify a refund deadline, how long should + // refunds be allowed by default? Added on top of the payment deadline. + // @since **v22** + default_refund_delay?: RelativeTime; + + // 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 on top of + // the refund deadline and afterwards subject to rounding + // via the ``default_wire_transfer_rounding_interval``. + // Optional @since **v22** (before the setting was mandatory). + // If not provided, the previous setting will now simply be preserved. + default_wire_transfer_delay?: RelativeTime; + + // How far should the wire deadline (if computed with the help of + // the ``default_wire_transfer_delay``) be rounded up to compute + // the ultimate wire deadline? + // @since **v22**, defaults to no rounding if not given. + default_wire_transfer_rounding_interval?: RoundingInterval; } @@ -1868,15 +1960,28 @@ Inspecting instances // Can always be overridden by the frontend on a per-order basis. use_stefan: boolean; + // If the frontend does NOT specify a payment deadline, how long should + // offers we make be valid by default? Added to the order creation + // time. + default_pay_delay: RelativeTime; + + // If the frontend does NOT specify a refund deadline, how long should + // refunds be allowed by default? Added to the payment deadline. + // @since **v22** + default_refund_delay: RelativeTime; + // 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. + // executing the wire transfer? This delay is added to the + // refund deadline and subject to rounding to the + // ``default_wire_transfer_rounding_interval``. 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_delay: RelativeTime; + // Default interval to which wire deadlines computed by + // adding the wire_transfer_delay on top of the refund + // deadline should be rounded up to. + // @since **v23** + default_wire_transfer_rounding_interval: RoundingInterval; // Authentication configuration. // Does not contain the token when token auth is configured. @@ -2694,12 +2799,29 @@ Adding products to the inventory // 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; + // Optional override to control whether fractional quantities are permitted. + // Defaults to the policy implied by ``unit``. + unit_allow_fraction?: boolean; + + // Override for the fractional precision level (0-6). Only relevant if + // ``unit_allow_fraction`` is true. Defaults come from ``unit``. + unit_precision_level?: Integer; + + // Preferred way to express inventory counts using "<integer>[.<fraction>]" syntax. + // Use "-1" for unlimited stock. Required unless ``total_stock`` is provided. + unit_total_stock?: string; + + // Legacy stock counter. Deprecated, use ``unit_total_stock`` instead. + // Still required when ``unit_total_stock`` is omitted. + total_stock?: Integer; + + // Preferred way to express the per-unit price of the product. Zero implies that + // the product is not sold separately or that the price must be supplied by the frontend. + // If non-zero, this price MUST include applicable taxes. + unit_price?: Amount; + + // Legacy price field. Deprecated; when present it must match ``unit_price``. + price?: Amount; // An optional base64-encoded product image. image?: ImageDataUrl; @@ -2707,12 +2829,6 @@ Adding products to the inventory // 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; @@ -2724,6 +2840,32 @@ Adding products to the inventory } + Clients SHOULD migrate to the new ``unit_*`` fields and treat ``total_stock`` and ``price`` + as deprecated compatibility shims. If both the legacy and the new representation are supplied, + their values must match. Omitting both ``unit_total_stock`` and ``total_stock`` (or both + ``unit_price`` and ``price``) results in a ``400 Bad Request``. + + ``unit_total_stock`` uses a fixed-point decimal string in the form ``INTEGER[.FRACTION]`` with + at most eight fractional digits. Scientific notation or special values such as ``NaN`` are not + accepted. Supply ``"-1"`` to represent unlimited stock. + + Fractional behaviour defaults to the value of ``unit``. The backend disables fractions for + ``Piece``, ``Set``, ``Custom``, ``WeightUnitMg`` and ``SizeUnitMm``. Other predefined units + allow fractional quantities with the following default precision levels: + + - Precision ``1``: ``WeightUnitG``, ``SizeUnitCm``, ``SurfaceUnitMm2``, ``VolumeUnitMm3``. + - Precision ``2``: ``WeightUnitOunce``, ``SizeUnitInch``, ``SurfaceUnitCm2``, + ``VolumeUnitInch3``, ``VolumeUnitOunce``, ``TimeUnitHour``, ``TimeUnitMonth``. + - Precision ``3``: ``WeightUnitTon``, ``WeightUnitKg``, ``WeightUnitPound``, ``SizeUnitM``, + ``SizeUnitDm``, ``SizeUnitFoot``, ``SurfaceUnitDm2``, ``SurfaceUnitFoot2``, ``VolumeUnitCm3``, + ``VolumeUnitLitre``, ``VolumeUnitGallon``, ``TimeUnitSecond``, ``TimeUnitMinute``, + ``TimeUnitDay``, ``TimeUnitWeek``. + - Precision ``4``: ``SurfaceUnitM2``, ``SurfaceUnitInch2``, ``TimeUnitYear``. + - Precision ``5``: ``VolumeUnitDm3``, ``VolumeUnitFoot3``. + - Precision ``6``: ``VolumeUnitM3``. + + Integrations can override these defaults by explicitly setting ``unit_allow_fraction`` and/or + ``unit_precision_level``. .. http:patch:: [/instances/$INSTANCE]/private/products/$PRODUCT_ID @@ -2774,17 +2916,25 @@ Adding products to the inventory // Unit in which the product is measured (liters, kilograms, packages, etc.). unit: string; + // Optional override to control whether fractional quantities are permitted. + unit_allow_fraction?: boolean; + + // Override for the fractional precision level (0-6). Only relevant if + // ``unit_allow_fraction`` is true. + unit_precision_level?: Integer; + // Categories into which the product belongs. // Used in the POS-endpoint. // Since API version **v16**. categories?: 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; + // Preferred way to express the per-unit price. Zero implies that + // the product is not sold separately or that the price must be supplied by the frontend. + // If non-zero, this price MUST include applicable taxes. + unit_price?: Amount; + + // Legacy price field. Deprecated; when present it must match ``unit_price``. + price?: Amount; // An optional base64-encoded product image. image?: ImageDataUrl; @@ -2792,11 +2942,12 @@ Adding products to the inventory // 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; + // Preferred way to express inventory counts using "<integer>[.<fraction>]" syntax. + // Use "-1" for unlimited stock. + unit_total_stock?: string; + + // Legacy stock counter. Deprecated, use ``unit_total_stock`` instead. + total_stock?: Integer; // Number of units of the product that were lost (spoiled, stolen, etc.). total_lost?: Integer; @@ -2812,6 +2963,9 @@ Adding products to the inventory } + The same compatibility rules for the ``unit_*`` fields and their deprecated counterparts apply + when patching an existing product. + Inspecting inventory ^^^^^^^^^^^^^^^^^^^^ @@ -2825,6 +2979,9 @@ Inspecting inventory :query limit: *Optional*. At most return the given number of results. Negative for descending by row ID, positive for ascending by row ID. Default is ``20``. Since protocol **v12**. :query offset: *Optional*. Starting ``product_serial_id`` for an iteration. Since protocol **v12**. + :query category_filter: *Optional*. Only returns products that are in a category where the category name contains the given text as a substring. Matching is case-insensitive. Since protocol **v23**. + :query name_filter: *Optional*. Only returns products where the product name contains the given text as a substring. Matching is case-insensitive. Since protocol **v23**. + :query description_filter: *Optional*. Only returns products where the product description contains the given text as a substring. Matching is case-insensitive. Since protocol **v23**. **Response:** @@ -2854,7 +3011,6 @@ Inspecting inventory // ``product_serial_id`` of the product in the database. product_serial: Integer; - // TODO: also return description/description_i18n here? } @@ -2891,15 +3047,22 @@ Inspecting inventory // Unit in which the product is measured (liters, kilograms, packages, etc.). unit: string; + // Does the backend allow fractional quantities for this unit? + unit_allow_fraction: boolean; + + // Maximum fractional precision (0-6) enforced for inventory operations. + unit_precision_level: Integer; + // Categories into which the product belongs. // Since API version **v16**. categories: 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 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. + unit_price: Amount; + + // Legacy price field kept for compatibility. Deprecated; equal to ``unit_price``. price: Amount; // An optional base64-encoded product image. @@ -2909,12 +3072,13 @@ Inspecting inventory // Optional since **v15**. 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). + // Legacy integer stock counter kept for compatibility. ``-1`` indicates unlimited stock. total_stock: Integer; + // Stock expressed using "<integer>[.<fraction>]" syntax with up to eight fractional digits. + // Use ``"-1"`` for unlimited stock. + unit_total_stock: string; + // Number of units of the product that have already been sold. total_sold: Integer; @@ -2990,11 +3154,18 @@ Inspecting inventory // 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. + // Does the backend allow fractional quantities for this unit? + unit_allow_fraction: boolean; + + // Maximum fractional precision (0-6) enforced for inventory operations. + unit_precision_level: Integer; + + // 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. + unit_price: Amount; + + // Legacy price field kept for compatibility. Deprecated; equal to ``unit_price``. price: Amount; // An optional base64-encoded product image. @@ -3003,12 +3174,13 @@ Inspecting inventory // 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. - // Optional, if missing treat as "infinite". + // Legacy integer stock counter kept for compatibility. ``-1`` indicates unlimited stock. total_stock?: Integer; + // Stock expressed using "<integer>[.<fraction>]" syntax with up to eight fractional digits. + // Use ``"-1"`` for unlimited stock. + unit_total_stock: string; + // Minimum age buyer must have (in years). minimum_age?: Integer; @@ -3063,7 +3235,7 @@ Reserving inventory :http:statuscode:`404 Not found`: The backend has does not know this product. :http:statuscode:`410 Gone`: - The backend does not have enough of product in stock. + The backend does not have enough of product in stock. Returns an `OutOfStockResponse`. **Details:** @@ -3078,11 +3250,19 @@ Reserving inventory // How long does the frontend intend to hold the lock? duration: RelativeTime; - // How many units should be locked? - quantity: Integer; + // Legacy integer quantity to lock. Deprecated; defaults to 1 if both + // ``quantity`` and ``unit_quantity`` are absent. + quantity?: Integer; + + // Preferred way to express the requested quantity using "<integer>[.<fraction>]" syntax. + unit_quantity?: string; } + At least one of ``quantity`` or ``unit_quantity`` must be supplied; omitting both defaults to a + quantity of one. ``unit_quantity`` follows the same decimal-string format described for + ``unit_total_stock``. + .. note:: The ``GNUNET_CRYPTO_random_timeflake()`` C API can be used @@ -3476,10 +3656,18 @@ Creating orders // Which product is requested (here mandatory!). product_id: string; - // How many units of the product are requested. - quantity: Integer; + // Legacy integer quantity. Deprecated; defaults to 1 if both + // ``quantity`` and ``unit_quantity`` are absent. + quantity?: Integer; + + // Preferred quantity string using "<integer>[.<fraction>]" syntax. + unit_quantity?: string; } + 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 { @@ -3503,12 +3691,18 @@ Creating orders // Product ID of an out-of-stock item. product_id: string; - // Requested quantity. + // Legacy integer quantity requested. Deprecated; see ``unit_requested_quantity``. requested_quantity: Integer; - // Available quantity (must be below ``requested_quantity``). + // Requested quantity using "<integer>[.<fraction>]" syntax with up to eight fractional digits. + unit_requested_quantity: string; + + // Legacy integer availability (must be below ``requested_quantity``). available_quantity: Integer; + // Available quantity using "<integer>[.<fraction>]" syntax with up to eight fractional digits. + unit_available_quantity: string; + // When do we expect the product to be again in stock? // Optional, not given if unknown. restock_expected?: Timestamp; @@ -3537,6 +3731,7 @@ Inspecting orders :query timeout_ms: *Optional*. Timeout in milliseconds to wait for additional orders if the answer would otherwise be negative (long polling). Only useful if ``limit`` is positive. Note that the merchant MAY still return a response that contains fewer than ``limit`` orders. :query session_id: *Optional*. Since protocol **v6**. Filters by session ID. :query fulfillment_url: *Optional*. Since protocol **v6**. Filters by fulfillment URL. + :query summary_filter: *Optional*. Only returns orders where the summary contains the given text as a substring. Matching is case-insensitive. Since protocol **v23**. **Response:** @@ -5816,9 +6011,12 @@ It has the following structure: // Map from IETF BCP 47 language tags to localized descriptions. description_i18n?: { [lang_tag: string]: string }; - // The number of units of the product to deliver to the customer. + // Legacy integer portion of the quantity to deliver defaults to 1 if not specified. quantity?: Integer; + // Preferred quantity string using "<integer>[.<fraction>]" syntax with up to eight fractional digits. + unit_quantity?: string; + // Unit in which the product is measured (liters, kilograms, packages, etc.). unit?: string; diff --git a/design-documents/071-auto-refresh.rst b/design-documents/071-auto-refresh.rst @@ -0,0 +1,138 @@ +DD 71: Auto-refresh +################### + +Summary +======= + +This document describes when the wallet should automatically refresh +non-dirty coins. + + +Motivation +========== + +The wallet must refresh non-dirty coins before they expire, least the +user looses the money. However, this should not be done too early to +avoid refresh fees and/or excessive load on the exchange. On the other +hand, we need to be careful to not hold off for too long and risk +the wallet not going online before the expiration time. + +We note that there obviously is no perfect solution, as at least in +principle the user could always not restart the wallet until the +expiration time. + + +Requirements +============ + +* Do not loose funds under most conditions +* Do not cause clearly avoidable refresh operations +* Try to educate the user if they are about to get into trouble +* Independently of any specific approach, the wallet + MUST spend those coins first that are earliest to + their expiration time within their equivalence class + as that is always the best way to avoid expiration. +* While lifetimes of denominations are often identical, + that may not always be the case. Theoretically, an + exchange could significantly increase or decrease the + deposit period at any time. The solution should + take this into consideration. + + +Proposed Solution +================= + +1. For each denomination, consider if a refresh would + lengthen the expiration date by more than a factor + of four (4x), that is if the deposit expiration time + of the denomination(s) we could currently withdraw + is more than 4x as long as what remains for the + denomination. If so, refresh + all coins of that denomination. + + + ..note:: + + This basically suggests that a refresh + would have a significant positive **impact**. + +2. For each denomination, consider if the remaining + deposit period is less than **6** months, if the + refresh fee would be zero, and if after refreshing + the deposit expiration time would exceed **12** months, + and if we are not on battery power. If so, refresh + all coins of that denomination. + + ..note:: + + This is again a significant impact, and it is basically + gratis for the user. + +3. For each denomination, consider if the remaining + deposit period is less than **3** months, and if + after refreshing the deposit expiration time would + be larger. If so, refresh all coins of that denomination. + If afterwards the expiration time exceeds **12** months, + show the user a warning: + + "This wallet was offline for too long. Make sure to + start it at least every **3 months** to avoid the + risk of loosing funds to expiration." + + ..note:: + + This is basically a last-minute effort (unless we have + an exchange with extremely short expiration periods). + We do not like getting into this situation, so it is + time to educate the user. + +4. Explicitly show a warning in the balances list of + the respective currency if the remaining deposit + period for any coin drops below 90 days. + Distinguish in the warning key causes: + 1) "We are offline and cannot expand the validity period." + 2) "The payment service provider does not offer longer + validity periods." + + ..note:: + + This should prevent us from getting into trouble if + e-cash is lost anyway. + + +Definition of Done +================== + +* Implemented in wallet-core +* Changes to interactions for signalling warnings to GUIs +* dev-experiments exist to trigger special alerts to users +* GUIs have been designed and tested + + +Alternatives +============ + +The wallet currently implements simple rules for auto-refresh: + +1. After 75% of a denomination's "deposit lifespan" has passed, + we do "auto-refresh check" for all coins of the exchange + +2. During this auto-refresh check, all coins that are >50% into + their deposit lifespan are auto-refreshed. + +This is risky as it does not consider absolute lifespans or user +behavior. + + +Drawbacks +========= + +* This approach does not (yet) consider user behavior. We could + theoretically learn from that. + + + +Discussion / Q&A +================ + +(This should be filled in with results from discussions on mailing lists / personal communication.) diff --git a/design-documents/072-products-units.rst b/design-documents/072-products-units.rst @@ -0,0 +1,378 @@ +DD 72: Products Units +##################### + +Summary +======= + +Introduce canonical ``unit_*`` metadata for merchant inventory so prices and +stock levels can be expressed with fractional precision while retaining legacy +integer fields for backwards compatibility. Provide guidance to wallets, PoS +terminals, and merchant tooling to keep UX coherent across integrations. + +Motivation +========== + +Bug reports revealed two conflicting requirements: + +* Products sold by measurable attributes (for example potatoes by kilogram) + need fractional support so customers can order 1.5 kg without hacks. +* Discrete products (for example “pieces” of cheese) must remain integer-only; + allowing 1.2 pc would break inventory management. + +The existing API exposes only integer fields (``quantity``, ``total_stock``, +``price``). Simply switching to floating-point values would enable nonsensical +orders and introduce rounding issues. After team discussion it was decided +that explicit ``unit_*`` metadata can be introduced for overall cleanliness of the +code base. + +Requirements +============ + +* **Preserve compatibility:** accept and emit the legacy integer fields while + marking them deprecated once ``unit_*`` alternatives exist. When both are + supplied the backend must check that values match. +* **Use a predictable format:** fixed-point decimal strings + ``INTEGER[.FRACTION]`` with up to eight fractional digits; reject scientific + notation and special floating-point tokens. +* **Provide backend-chosen defaults per unit identifier** so new front-ends + can present appropriate UI without manual configuration. +* **Allow merchants to override** the default policy through explicit fields. +* **Update every affected endpoint** (GET/POST/PATCH products, PoS inventory, + lock, order creation, contract products) to expose and accept the new + metadata. +* **Document expectations** for merchant back-ends, PoS clients, and wallets + to ensure consistent behaviour across the ecosystem. + +Proposed Solution +================= + +1. **Extend product schemas** with optional metadata: + + * ``unit_allow_fraction`` (boolean) + * ``unit_precision_level`` (integer 0–6) + * ``unit_price`` (fixed-point decimal string) + * ``unit_total_stock`` (fixed-point decimal string, ``-1`` keeps the + “infinite” semantics) + + Legacy ``price`` and ``total_stock`` remain, but become compatibility shims and + must match the new values whenever present. + +2. **Accept** ``unit_quantity`` wherever clients submit quantities (inventory + locks, ``inventory_products``). The backend converts the decimal string into + the legacy ``quantity`` and new ``quantity_frac`` pair for storage so existing + clients keep working. + +3. **Return both representations** in all read APIs so integrators can migrate + at their own pace. + +4. **Default backend policies** + + Any backend unit identifier that is **not** listed in the table below SHALL + be treated as *Custom*: ``unit_allow_fraction`` = false, + ``unit_precision_level`` = 0, and both default labels (long/short) echo the + merchant-supplied string. + +.. list-table:: Default backend policies + :widths: 20 10 10 30 30 + :header-rows: 1 + + * - BackendStr + - Type + - Precision + - Default label (long) + - Default label (short) + * - Piece + - int + - 0 + - piece + - pc + * - Set + - int + - 0 + - set + - set + * - SizeUnitCm + - float + - 1 + - centimetre + - cm + * - SizeUnitDm + - float + - 3 + - decimetre + - dm + * - SizeUnitFoot + - float + - 3 + - foot + - ft + * - SizeUnitInch + - float + - 2 + - inch + - in + * - SizeUnitM + - float + - 3 + - metre + - m + * - SizeUnitMm + - int + - 0 + - millimetre + - mm + * - SurfaceUnitCm2 + - float + - 2 + - square centimetre + - cm² + * - SurfaceUnitDm2 + - float + - 3 + - square decimetre + - dm² + * - SurfaceUnitFoot2 + - float + - 3 + - square foot + - ft² + * - SurfaceUnitInch2 + - float + - 4 + - square inch + - in² + * - SurfaceUnitM2 + - float + - 4 + - square metre + - m² + * - SurfaceUnitMm2 + - float + - 1 + - square millimetre + - mm² + * - TimeUnitDay + - float + - 3 + - day + - d + * - TimeUnitHour + - float + - 2 + - hour + - h + * - TimeUnitMinute + - float + - 3 + - minute + - min + * - TimeUnitMonth + - float + - 2 + - month + - mo + * - TimeUnitSecond + - float + - 3 + - second + - s + * - TimeUnitWeek + - float + - 3 + - week + - wk + * - TimeUnitYear + - float + - 4 + - year + - yr + * - VolumeUnitCm3 + - float + - 3 + - cubic centimetre + - cm³ + * - VolumeUnitDm3 + - float + - 5 + - cubic decimetre + - dm³ + * - VolumeUnitFoot3 + - float + - 5 + - cubic foot + - ft³ + * - VolumeUnitGallon + - float + - 3 + - gallon + - gal + * - VolumeUnitInch3 + - float + - 2 + - cubic inch + - in³ + * - VolumeUnitLitre + - float + - 3 + - litre + - L + * - VolumeUnitM3 + - float + - 6 + - cubic metre + - m³ + * - VolumeUnitMm3 + - float + - 1 + - cubic millimetre + - mm³ + * - VolumeUnitOunce + - float + - 2 + - fluid ounce + - fl oz + * - WeightUnitG + - float + - 1 + - gram + - g + * - WeightUnitKg + - float + - 3 + - kilogram + - kg + * - WeightUnitMg + - int + - 0 + - milligram + - mg + * - WeightUnitOunce + - float + - 2 + - ounce + - oz + * - WeightUnitPound + - float + - 3 + - pound + - lb + * - WeightUnitTon + - float + - 3 + - metric tonne + - t + * - **Custom** + - int + - 0 + - *merchant string* + - *merchant string* + +5. **Quantity presentation in wallets and orders** + + When displaying order details or cart lines, wallet and POS front-ends + **MUST use the short unit label** from the table above, appended to the + numeric value with a non-breaking thin space (U+202F). Trailing zeros + *up to* the declared ``unit_precision_level`` **MUST be trimmed**, but the + displayed precision **MUST NOT** exceed the declared level. Examples:: + + 1.500 kg → shown as 1.5 kg + 3.00 pc → shown as 3 pc + + For precision 0 units the fractional part is omitted entirely. + +6. **Locale-aware unit translation rules for wallets** + + Wallets **SHOULD** offer users the option to view quantities in familiar + measurement systems. The following guidance applies: + + * Detect the buyer locale using the platform-standard mechanism (e.g. + ``navigator.language`` in browsers or OS locale on mobile). Only when the + locale **primary region** is in the CLDR “IU-customary group” + (``US``, ``LR``, ``MM``, ``GB``) **SHALL** conversions default to + imperial/US-customary, and vice-versa when the merchant lists imperial + units but the buyer locale is SI-centred. + + * Supported automatic conversions and factors (SI -> US and US -> SI): + + .. list-table:: Supported automatic conversions and factors + :widths: 40 30 30 + :header-rows: 1 + + * - SI unit + - US/imperial unit + - factor + * - kilogram (``kg``) + - pound (``lb``) + - 2.20462 + * - gram (``g``) + - ounce (``oz``) + - 0.035274 + * - litre (``L``) + - fluid ounce (``fl oz``) + - 33.814 + * - metre (``m``) + - foot (``ft``) + - 3.28084 + * - square metre (``m²``) + - square foot (``ft²``) + - 10.7639 + * - cubic metre (``m³``) + - cubic foot (``ft³``) + - 35.3147 + + * Conversions **MUST** round to the wallet's target + ``unit_precision_level`` using bankers-rounding to minimise cumulative + error. + + * When a converted value is displayed it **SHOULD** be prefixed with + “ca.” (or ``≈`` symbol) and rendered in a visually subdued style (e.g. 60% opacity) to + signal approximation; the merchant-provided unit remains the authoritative + primary value. + + * The original backend value **MUST** be preserved in the contract terms; + conversions are *presentation-only*. + + * Wallets **SHOULD** expose a global *numeric-system* setting in their + preferences with the values ``off``, ``automatic``, ``SI``, and ``imperial``. + + - **off** – never perform unit conversions; display exactly the merchant-supplied units. + - **automatic** – apply the locale heuristic described above (imperial for ``US``, ``GB``, ``LR``, ``MM``; SI otherwise). + - **SI** – always display conversion of quantities in SI units (no conversion if the merchant already uses SI). + - **imperial** – always display conversion of quantities converted to imperial/US-customary units (no conversion if the merchant already uses imperial). + +Definition of Done +================== + +(Only applicable to design documents that describe a new feature. While the +DoD is not satisfied yet, a user-facing feature **must** be behind a feature +flag or dev-mode flag.) + +* Merchant backend accepts and emits the new metadata for product CRUD, + inventory locks, and order creation. +* Merchant SPAA has updated screen for product creation, which facilitates the + default units, updated products table to use new ``unit_total_stock`` string, + order can be created with fractional quantities. +* POS and wallet reference implementations render fractional quantities + according to ``unit_allow_fraction`` / ``unit_precision_level``, allows + to create orders with fractional quantities of products. +* Legacy clients continue to function using the integer fields, with + automated tests ensuring that canonical and legacy values stay in sync. +* Wallets follows points 5 and 6 of Proposed Solution. + +Alternatives +============ + +* Replace integers with floating-point numbers. This was ruled out because it + cannot prevent semantically invalid requests (for example 1.2 pieces) and + reintroduces floating-point rounding issues into price calculations. + +Drawbacks +========= + +* Payloads grow slightly because responses include both canonical decimal + strings and legacy integers. +* Integrations must update their tooling to emit and validate decimal strings, + which adds complexity compared to sending plain integers. + +Discussion / Q&A +================ diff --git a/design-documents/index.rst b/design-documents/index.rst @@ -82,4 +82,6 @@ Design documents that start with "XX" are considered deprecated. 068-tokens-roadmap 069-exchange-base-url-completion 070-alias-directory-mailbox + 071-auto-refresh + 072-products-units 999-template diff --git a/frags/list-of-dependencies.rst b/frags/list-of-dependencies.rst @@ -22,7 +22,7 @@ - GNU libmicrohttpd >= 0.9.71 -- GNUnet >= 0.20 (from `source tarball <http://ftpmirror.gnu.org/gnunet/>`__) +- GNUnet >= 0.25.2 (from `source tarball <http://ftpmirror.gnu.org/gnunet/>`__) - Python3 with ``jinja2`` diff --git a/manpages/taler-merchant-passwd.1.rst b/manpages/taler-merchant-passwd.1.rst @@ -6,7 +6,7 @@ taler-merchant-passwd(1) Name ==== - **taler-merchant-passwd** - reset password of existing instance + **taler-merchant-passwd** - reset password of existing instance and/or create admin instance Synopsis @@ -29,6 +29,11 @@ of existing Taler instances. The password must either be specified as the last command-line argument or in the TALER_MERCHANT_PASSWORD environment variable. +Usually, the instance for which the password is being set must +already exist. However, as a special exception, if the instance +specified is the "admin" instance, then it is created (with +sensible defaults) if it does not yet exist. + Its options are as follows: **-c** *FILENAME* \| **--config=**\ ‌\ *FILENAME* @@ -40,7 +45,7 @@ Its options are as follows: **-i** *NAME* \| **--instance**\ \ *NAME* Specifies the name of the instance for which the password should be - updated. If not given, the "default" instance is modified. + updated. If not given, the "admin" instance is modified. **-L** *LOGLEVEL* \| **--loglevel=**\ ‌\ *LOGLEVEL* Specifies the log level to use. Accepted values are: ``DEBUG``, ``INFO``, diff --git a/manpages/taler-merchant.conf.5.rst b/manpages/taler-merchant.conf.5.rst @@ -176,6 +176,43 @@ LEGAL_PRESERVATION How long do we keep data in the database for tax audits after the transaction has completed? Default is 10 years. +DEFAULT_PAY_DELAY + What is the default payment delay for new instances. This is how long the + customer has to pay the order before the offer expires. + This backend default can be changed per-instance and then still overridden per-order. + Defaults to one day if not specified in the configuration. + +DEFAULT_REFUND_DELAY + What is the default refund delay for new instances. This is how long the + merchant can grant refunds to the customer. Is added on top of the + payment deadline (for an actual order). + This backend default can be changed per-instance and then still overridden per-order. + If the order overrides the wire transfer deadline and does not + specify a refund deadline and if the DEFAULT_REFUND_DELAY would + imply a longer refund deadline, then the wire transfer deadline + is used for the refund deadline. + Defaults to 15 days if not specified in the configuration. + +DEFAULT_WIRE_TRANSFER_DELAY + What is the default wire transfer delay for new instances. This is how long the + exchange has to settle the payment with a wire transfer, enabling refunds and aggregation + of multiple transfers to happen until this time. + The value given is added on top of the refund deadline and is then + subject to rounding as per DEFAULT_WIRE_TRANSFER_ROUNDING_INTERVAL. + This backend default can be changed per-instance and then still overridden per-order. + Defaults to one month if not specified in the configuration. + +DEFAULT_WIRE_TRANSFER_ROUNDING_INTERVAL + Specifies to what time interval a wire transfer deadline computed + via the DEFAULT_WIRE_TRANSFER_DELAY should be rounded up. Supported + values are NONE, SECOND, MINUTE, HOUR, DAY, WEEK, MONTH, QUARTER and + YEAR, each implying that wire transfer deadline computed + should be rounded up to the respective end of the next interval + using the local timezone of the merchant backend. + This backend default can be changed per-instance. + Rounding does not apply if the wire deadline is overridden per-order. + Defaults to NONE (no rounding up) if not specified in the configuration. + FORCE_AUDIT Force the merchant to report every transaction to the auditor (if the exchange has an auditor)? Default is ``NO``. @@ -196,6 +233,14 @@ HELPER_EMAIL STRICT_PROTOCOL_V19 Set to YES to strictly enforce protocol version 19 or later. Transient option for development. +PAYMENT_TARGET_TYPES + Space-separated list of allowed payment target types (like bitcoin, iban or x-taler-bank). + Defaults to "*" which means no restrictions if not specified. + +PAYMENT_TARGET_REGEX + POSIX regular expression imposing additional restrictions on the "payto://"-URIs allowed + for bank accounts of instances of this system. For example, "payto://iban/CH.*" would + restrict the system to only Swiss IBAN accounts. Optional, no restrictions if not set. MERCHANT KYCCHECK OPTIONS ------------------------- diff --git a/taler-merchant-manual.rst b/taler-merchant-manual.rst @@ -399,6 +399,16 @@ There is no need to actually run a Taler exchange to use the Taler merchant backend -- all the merchant needs from the Taler exchange is a few headers and libraries! +.. note:: + + There is an additional **optional** dependency that you could install to + obtain support for tax-deductable donations. This is only useful for + charities and only in countries with tax authorities that operate a Donau to + register charities and accept Taler-style digitally signed donation + statements. As of right now, we are pretty sure that list is right now + empty. But, if you want to experiment with Taler-style donation statmenets, + you need to install Donau after the exchange and before the merchant. + .. include:: frags/install-before-check.rst .. include:: frags/installing-taler-merchant.rst @@ -502,8 +512,8 @@ To run the Taler backend on TCP port 9966 (the default), use: Currency ^^^^^^^^ -Which currency the Web shop deals in, i.e. “EUR” or “USD”, is -specified using the option +Which currency the SPA uses by default is +specified using the option: .. code-block:: ini @@ -511,7 +521,7 @@ specified using the option CURRENCY = EUR # or USD, ... When testing with the Taler demonstration exchange at -https://exchange.demo.taler.net/ you must set this +https://exchange.demo.taler.net/ you probably want to set this value to ``KUDOS``: .. code-block:: ini @@ -519,6 +529,11 @@ value to ``KUDOS``: [MERCHANT] CURRENCY = KUDOS +The merchant backend is already multi-currency capable, and will allow you to +create orders in all currencies for which an exchange is configured, not just +the default currency. However, the Web interface does not yet offer +multi-currency support and often only supports using the default currency. + .. note:: When using the Debian/Ubuntu packages, these options should be @@ -709,6 +724,13 @@ merchant backend as ``$USER`` using (to provide a trivial example): $ taler-merchant-wirewatch & $ taler-merchant-depositcheck & $ taler-merchant-exchangekeyupdate & + $ taler-merchant-reconciliation & + +.. note:: + + If you compiled the merchant backend with support for donation + statements via Donau, you need to additionally launch + ``taler-merchant-donaukeyupdate``. To ensure these processes run always in the background and also after rebooting, you should use systemd, cron or some other init system of your @@ -825,9 +847,17 @@ interface. Alternatively, you can also use the ``wget`` commands given below. Regardless of which approach you use, the first step for using the backend involves the creation of the ``admin`` instance. The ``admin`` instance can also create, configure or delete other instances, similar to the ``root`` -account on UNIX. When no instance exists and ``taler-merchant-httpd`` was -started without the ``--auth`` option, then the backend is reachable without -any access control (unless you configured some in the reverse proxy). +account on UNIX. When no instance exists, then the backend is reachable +without any access control (unless you configured some in the reverse proxy). + +.. note:: + + If you created a non-admin instance first, you cannot create an ``admin`` + instance via the SPA anymore. In this case, you can only create an + administrative account by using the command-line. By invoking + ``taler-merchant-passwd --instance=admin $PASSWORD`` you can set both the + password and create an ``admin`` instance if it does not yet exist. + However, for non-admin instances, you can only set the password with this tool. The following documentation shows how to handle any instance. Thus, if you want to have multiple instances, you may need to perform the steps multiple @@ -868,6 +898,76 @@ and the desired access token, click ``confirm``. You can change the instance settings later via the ``Settings`` entry in the menu on the left. +Instance settings +----------------- + +The settings dialog allows you to select an image to be used as a logo +for your shop. Wallets may use that logo when showing contracts to +highlight to customers which shop they are buying from. + +The settings dialog allows you to specify the address of your business +and the jurisdiction the shop is under. Both will be embedded into the +contracts and may be shown by the Taler wallet to customers that want +to know these details. + +You must also configure whether you intend to pay transaction fees, +or whether the customer is required to pay for any payment fees. If +you do not cover the fees, the fees will be shown separately to the +customer and added to the total of each order, which may discourage +consumers from using the Taler payment method. The specific +magnitude of the fees cannot be configured here, as it depends on +the amount of the order and is dynamically computed. Regardless of +what you specify here, the front-end can override the acceptable +fee amount for each order it creates. + +.. note:: + + Details on the acceptable fee calcuation + are described in the Taler design document 47. + +Finally, you need to specify several settings relating to default +deadlines. + + (1) The "Default payment delay" specifies when an offer expires. The + customer basically has this amount of time to pay, or the backend will + refuse the payment and require the customer to get a new quote. + + (2) The "Default refund delay" specifies how long the customer may receive + refunds. The refund period is cummulative on top of the "Default payment + delay". Thus, the refund period ends independently of when the customer + actually paid for the order. The exchange will **not** wire the funds to the + merchant before the refund deadline lapses, as after the funds have been + wired refunds using Taler are no longer possible. + + (3) The "Default wire transfer delay" specifies how soon the exchange + **must** wire the funds **after** the refund deadline. The delay is again + cummulative on top of the "Default payment delay" and the "Default refund + delay". However, the resulting time is still not the actual wire + deadline, as first the "Default wire rounding interval" is also considered. + + (4) The "Default wire rounding interval" specifies to what period the + wire deadline should be rounded up to. The ultimate wire deadline is + computed by adding the default payment, rounding and wire delays to + the current time and rounding the resulting timestamp to the + "Default wire rounding interval". Typical values include + end-of-day, end-of-week, end-of-month, end-of-quarter or end-of-year. + +.. note:: + + The wire deadline is rounded using the local timezone of the Taler merchant + backend server, so if you want end-of-day payments make sure to run your + merchant backend in your own timezone. + +Specifying larger values for the wire transfer delay and the wire rounding +interval allows the exchange to aggregate more payments into larger wire +transfers. The exchange is required by the protocol to initiate the wire +transfer **before** the wire transfer deadline. + +All of the computed deadlines (payment, refund and wire transfer) +are just defaults and can be modified by frontends for any +specific order. + + Instance setup without the Web interface ---------------------------------------- @@ -886,8 +986,9 @@ interface create a file ``instance.json`` with an "auth": { "method" : "external"} , "jurisdiction": { "country" : "zz" }, "use_stefan": true, - "default_wire_transfer_delay": { "d_ms" : 1209600000 }, "default_pay_delay": { "d_ms" : 1209600000 } + "default_refund_delay": { "d_ms" : 1209600000 } + "default_wire_transfer_delay": { "d_ms" : 1209600000 }, } The ``name`` field will be shown as the name of your shop. The ``address``