taler-docs

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

commit fad6e72d1e778cfa0c6772cae1e16d8f544267cb
parent 89cf63785ee4cd8c7838cebc2046374e7f1b2f51
Author: bohdan-potuzhnyi <bohdan.potuzhnyi@gmail.com>
Date:   Wed, 26 Nov 2025 14:30:42 +0100

adding actual changes from the update-inventory-logic branch + info on get /images

Diffstat:
Mcore/api-merchant.rst | 263++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------
1 file changed, 236 insertions(+), 27 deletions(-)

diff --git a/core/api-merchant.rst b/core/api-merchant.rst @@ -2616,6 +2616,184 @@ Taler merchant backend to process payments *without* using its inventory management. +Managing measurement units +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. http:get:: [/instances/$INSTANCE]/private/units + + Returns the list of measurement units available to an instance. + + **Required permission:** ``units-read`` + + **Response:** + + :http:statuscode:`200 OK`: + The backend returned the unit catalog. The body is a `UnitListResponse`. + + **Details:** + + .. ts:def:: UnitListResponse + + interface UnitListResponse { + units: MerchantUnit[]; + } + + .. ts:def:: MerchantUnit + + interface MerchantUnit { + // Unique serial for the unit. + unit_serial: Integer; + + // Short identifier used in product definitions. + unit: string; + + // Human-readable long label. + unit_name_long: string; + + // Human-readable short label. + unit_name_short: string; + + // Optional translations for the long label. + unit_name_long_i18n?: { [lang_tag: string]: string }; + + // Optional translations for the short label. + unit_name_short_i18n?: { [lang_tag: string]: string }; + + // Whether fractional quantities are allowed for this unit. + unit_allow_fraction: boolean; + + // Maximum fractional precision (0-6) enforced for this unit. + unit_precision_level: Integer; + + // Whether the unit is currently active. + unit_active: boolean; + + // True if the unit is provided by the backend and cannot be removed. + unit_builtin: boolean; + } + +.. http:get:: [/instances/$INSTANCE]/private/units/$UNIT + + Fetch details for a single measurement unit. + + **Required permission:** ``units-read`` + + **Response:** + + :http:statuscode:`200 OK`: + The backend returned the unit definition. The body is a `MerchantUnit`. + :http:statuscode:`404 Not found`: + The unit is unknown to the backend. + +.. http:post:: [/instances/$INSTANCE]/private/units + + Create a custom measurement unit or reactivate a previously disabled one. + + **Required permission:** ``units-write`` + + **Request:** + + The request must be a `UnitAddRequest`. + + **Response:** + + :http:statuscode:`204 No content`: + The backend added the unit. + :http:statuscode:`409 Conflict`: + A built-in unit with the same short name already exists. + + .. ts:def:: UnitAddRequest + + interface UnitAddRequest { + // Short identifier to reference the unit from products and orders. + unit: string; + + // Human-readable long label (e.g. "kilogram"). + unit_name_long: string; + + // Human-readable short label (e.g. "kg"). + unit_name_short: string; + + // Optional translations for the long label keyed by BCP 47 language tags. + unit_name_long_i18n?: { [lang_tag: string]: string }; + + // Optional translations for the short label keyed by BCP 47 language tags. + unit_name_short_i18n?: { [lang_tag: string]: string }; + + // Defaults to false; set to true to enable fractional quantities. + unit_allow_fraction?: boolean; + + // Fractional precision (0-6). Ignored when ``unit_allow_fraction`` is false. + unit_precision_level?: Integer; + + // Defaults to true. + unit_active?: boolean; + } + +.. http:patch:: [/instances/$INSTANCE]/private/units/$UNIT + + Update attributes of a measurement unit. + + **Required permission:** ``units-write`` + + **Request:** + + The request must be a `UnitPatchRequest`. + + **Response:** + + :http:statuscode:`204 No content`: + The backend updated the unit. + :http:statuscode:`404 Not found`: + The unit is unknown to the backend. + + Built-in units allow changing ``unit_allow_fraction``, ``unit_precision_level``, and + ``unit_active``; other fields are immutable for built-ins. + + .. ts:def:: UnitPatchRequest + + interface UnitPatchRequest { + // Updated human-readable long label. + unit_name_long?: string; + + // Updated human-readable short label. + unit_name_short?: string; + + // Updated translations for the long label keyed by BCP 47 language tags. + unit_name_long_i18n?: { [lang_tag: string]: string }; + + // Updated translations for the short label keyed by BCP 47 language tags. + unit_name_short_i18n?: { [lang_tag: string]: string }; + + // Override to allow or forbid fractional quantities. + unit_allow_fraction?: boolean; + + // Override for the fractional precision (0-6). Ignored if fractions are disabled. + unit_precision_level?: Integer; + + // Toggle whether the unit is active. + unit_active?: boolean; + } + + Fractional precision is capped at six decimal places. Disabling + ``unit_allow_fraction`` forces ``unit_precision_level`` to zero. + +.. http:delete:: [/instances/$INSTANCE]/private/units/$UNIT + + Remove a custom unit from an instance. + + **Required permission:** ``units-write`` + + **Response:** + + :http:statuscode:`204 No content`: + The unit was removed. + :http:statuscode:`404 Not found`: + The unit is unknown to the backend. + :http:statuscode:`409 Conflict`: + Built-in units cannot be deleted. + + Managing product categories ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -2841,12 +3019,13 @@ Adding products to the inventory // 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; + // Preferred way to express the per-unit price of the product. Supply at least one entry; + // the first entry represents the base price and MUST include applicable taxes. + // Zero implies that the product is not sold separately or that the price must be supplied + // by the frontend. + unit_price?: Amount[]; - // Legacy price field. Deprecated; when present it must match ``unit_price``. + // Legacy price field. Deprecated; when present it must match the first element of ``unit_price``. price?: Amount; // An optional base64-encoded product image. @@ -2869,10 +3048,11 @@ 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_price`` and ``price``) results in a ``400 Bad Request``. When only ``price`` is given, + the backend treats it as a one-element ``unit_price`` array. ``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 + at most six 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 @@ -2954,12 +3134,13 @@ Adding products to the inventory // Since API version **v16**. categories?: Integer[]; - // 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; + // Preferred way to express the per-unit price. Supply at least one entry; + // the first entry represents the base price and MUST include applicable taxes. + // Zero implies that the product is not sold separately or that the price must be supplied + // by the frontend. + unit_price?: Amount[]; - // Legacy price field. Deprecated; when present it must match ``unit_price``. + // Legacy price field. Deprecated; when present it must match the first element of ``unit_price``. price?: Amount; // An optional base64-encoded product image. @@ -3083,12 +3264,12 @@ Inspecting inventory // Since API version **v16**. categories: 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; + // Price tiers for this product. The first entry represents the base price and MUST include + // applicable taxes. Zero implies the product is not sold separately or that the price is not + // fixed, and must be supplied by the front-end. + unit_price: Amount[]; - // Legacy price field kept for compatibility. Deprecated; equal to ``unit_price``. + // Legacy price field kept for compatibility. Deprecated; equal to the first element of ``unit_price``. price: Amount; // An optional base64-encoded product image. @@ -3101,7 +3282,7 @@ Inspecting inventory // 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. + // Stock expressed using "<integer>[.<fraction>]" syntax with up to six fractional digits. // Use ``"-1"`` for unlimited stock. unit_total_stock: string; @@ -3186,12 +3367,12 @@ Inspecting inventory // 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; + // Price tiers for this product. The first entry represents the base price and MUST include + // applicable taxes. Zero implies the product is not sold separately or that the price is not + // fixed, and must be supplied by the front-end. + unit_price: Amount[]; - // Legacy price field kept for compatibility. Deprecated; equal to ``unit_price``. + // Legacy price field kept for compatibility. Deprecated; equal to the first element of ``unit_price``. price: Amount; // An optional base64-encoded product image. @@ -3203,7 +3384,7 @@ Inspecting inventory // 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. + // Stock expressed using "<integer>[.<fraction>]" syntax with up to six fractional digits. // Use ``"-1"`` for unlimited stock. unit_total_stock: string; @@ -3226,6 +3407,34 @@ Inspecting inventory } +Fetching product images +^^^^^^^^^^^^^^^^^^^^^^^ + +.. http:get:: /products/$IMAGE_HASH/image + + Returns a stored product image by its content hash. The hash is the lowercase + hexadecimal SHA-256 digest of the base64-encoded image data supplied in + ``image`` during product creation or update. + + **Required permission:** none (public endpoint) + + **Response:** + + :http:statuscode:`200 OK`: + The body is a `ProductImageResponse`. + :http:statuscode:`400 Bad Request`: + The hash is not a valid hex-encoded SHA-256 digest. + :http:statuscode:`404 Not found`: + No image is known for the given hash. + + .. ts:def:: ProductImageResponse + + interface ProductImageResponse { + // Data URL containing the product image as stored in the backend. + image: ImageDataUrl; + } + + Reserving inventory ^^^^^^^^^^^^^^^^^^^ @@ -3734,13 +3943,13 @@ Creating orders // Legacy integer quantity requested. Deprecated; see ``unit_requested_quantity``. requested_quantity: Integer; - // Requested quantity using "<integer>[.<fraction>]" syntax with up to eight fractional digits. + // Requested quantity using "<integer>[.<fraction>]" syntax with up to six 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. + // Available quantity using "<integer>[.<fraction>]" syntax with up to six fractional digits. unit_available_quantity: string; // When do we expect the product to be again in stock? @@ -6092,7 +6301,7 @@ It has the following structure: // 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. + // Preferred quantity string using "<integer>[.<fraction>]" syntax with up to six fractional digits. unit_quantity?: string; // Unit in which the product is measured (liters, kilograms, packages, etc.).