taler-docs

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

post-private-orders.rst (18868B)


      1 .. _merchant-post-private-orders:
      2 
      3 .. http:post:: [/instances/$INSTANCE]/private/orders
      4 
      5   Create a new order that a customer can pay for.
      6 
      7   This request is **not** idempotent unless an ``order_id`` is explicitly specified.
      8   However, while repeating without an ``order_id`` will create another order, that is
      9   generally pretty harmless (as long as only one of the orders is returned to the wallet).
     10 
     11   .. note::
     12 
     13     This endpoint does not return a URL to redirect your user to confirm the
     14     payment.  To get this URL use either
     15     :http:get:`[/instances/$INSTANCE]/orders/$ORDER_ID` (with
     16     ``taler_pay_uri`` in the `StatusUnpaidResponse`), or
     17     :http:get:`[/instances/$INSTANCE]/private/orders/$ORDER_ID` with the
     18     ``taler_pay_uri`` in the `CheckPaymentUnpaidResponse`). That said,
     19     it is also possible to construct the URL by combining the base URL
     20     with the information from the `PostOrderResponse`.
     21     The API is structured this way since the payment redirect URL is not
     22     unique for every order: there might be varying parameters such as the
     23     session id.
     24 
     25   **Required permission:** ``orders-write``
     26 
     27   **Request:**
     28 
     29   The request must be a `PostOrderRequest`.
     30 
     31   **Response:**
     32 
     33   :http:statuscode:`200 OK`:
     34     The backend has successfully created the proposal.  The response is a
     35     :ts:type:`PostOrderResponse`.
     36   :http:statuscode:`404 Not found`:
     37     Possible reasons are:
     38 
     39     (1) The order given used products from the inventory, but those were
     40         not found in the inventory.
     41     (2) The merchant instance is unknown (including possibly the instance
     42         being not configured for new orders).
     43     (3) The wire method specified is not supported by the backend.
     44     (4) An OTP device ID was specified and is unknown.
     45 
     46     Details in the error code.
     47     NOTE: currently the client has no good way to find out which product
     48     is not in the inventory, we MAY want to specify that in the reply.
     49   :http:statuscode:`409 Conflict`:
     50     A different proposal already exists under the specified order ID,
     51     or the requested currency is not supported by this backend. Details in
     52     the error code.
     53   :http:statuscode:`410 Gone`:
     54     The order given used products from the inventory that are out of stock.
     55     The response is a :ts:type:`OutOfStockResponse`.
     56   :http:statuscode:`451 Unavailable for Legal Reasons`:
     57     The order could not be created because of legal
     58     reasons, specifically no exchange would accept
     59     a payment at this time because we have not yet
     60     satisfied the respective legal requirements.
     61     The :ref:`KYC status <merchantkycstatus>` API
     62     can be used to determine details about how to
     63     proceed with the KYC process.
     64     Since **v25**, the body is an
     65     `OrderRefusedErrorDetailResponse` with an error
     66     code of ``MERCHANT_PRIVATE_POST_ORDERS_AMOUNT_EXCEEDS_LEGAL_LIMITS``.
     67 
     68   **Details:**
     69 
     70   .. ts:def:: PostOrderRequest
     71 
     72     interface PostOrderRequest {
     73       // The order must at least contain the minimal
     74       // order detail, but can override all.
     75       order: Order;
     76 
     77       // If set, the backend will then set the refund deadline to the
     78       // payment deadline plus the specified delay.
     79       // If it's not set, the default value of the backend might be
     80       // used. Note that both this value and the backend default
     81       // will be ignored if ``refund_deadline`` is set in ``order``
     82       // as the ``refund_deadline`` takes precedence.
     83       // A value of "forever" is not allowed.
     84       refund_delay?: RelativeTime;
     85 
     86       // Specifies the payment target preferred by the client. Can be used
     87       // to select among the various (active) wire methods supported by the instance.
     88       payment_target?: string;
     89 
     90       // The session for which the payment is made (or replayed).
     91       // Only set for session-based payments.
     92       // Since protocol **v6**.
     93       session_id?: string;
     94 
     95       // Specifies that some products are to be included in the
     96       // order from the inventory.  For these inventory management
     97       // is performed (so the products must be in stock) and
     98       // details are completed from the product data of the backend.
     99       inventory_products?: MinimalInventoryProduct[];
    100 
    101       // Specifies a lock identifier that was used to
    102       // lock a product in the inventory.  Only useful if
    103       // ``inventory_products`` is set.  Used in case a frontend
    104       // reserved quantities of the individual products while
    105       // the shopping cart was being built.  Multiple UUIDs can
    106       // be used in case different UUIDs were used for different
    107       // products (i.e. in case the user started with multiple
    108       // shopping sessions that were combined during checkout).
    109       lock_uuids?: string[];
    110 
    111       // Should a token for claiming the order be generated?
    112       // False can make sense if the ORDER_ID is sufficiently
    113       // high entropy to prevent adversarial claims (like it is
    114       // if the backend auto-generates one). Default is 'true'.
    115       // Note: This is NOT related to tokens used for subscriptins or discounts.
    116       create_token?: boolean;
    117 
    118       // OTP device ID to associate with the order.
    119       // This parameter is optional.
    120       otp_id?: string;
    121 
    122     }
    123 
    124   The `Order` object represents the starting point for new `ContractTerms`.
    125   After validating and sanatizing all inputs, the merchant backend will add
    126   additional information to the order and create a new `ContractTerms` object
    127   that will be stored in the database.
    128 
    129   .. ts:def:: Order
    130 
    131     type Order = (OrderV1 | OrderV0) & OrderCommon;
    132 
    133   .. ts:def:: OrderV1
    134 
    135     interface OrderV1 {
    136       // Version 1 order support discounts and subscriptions.
    137       // https://docs.taler.net/design-documents/046-mumimo-contracts.html
    138       // @since protocol **v21**
    139       version: 1;
    140 
    141       // List of contract choices that the customer can select from.
    142       // @since protocol **v21**
    143       choices?: OrderChoice[];
    144     }
    145 
    146   .. ts:def:: OrderV0
    147 
    148     interface OrderV0 {
    149       // Optional, defaults to 0 if not set.
    150       version?: 0;
    151 
    152       // Total price for the transaction, including tip. The exchange will
    153       // subtract deposit fees from that amount before transferring it to
    154       // the merchant.
    155       amount: Amount;
    156 
    157       // Optional tip amount. Must match the currency of ``amount``.
    158       // Since protocol **v25**.
    159       tip?: Amount;
    160 
    161       // Maximum total deposit fee accepted by the merchant for this contract.
    162       // Overrides defaults of the merchant instance.
    163       max_fee?: Amount;
    164     }
    165 
    166   .. ts:def:: OrderCommon
    167 
    168     interface OrderCommon {
    169       // Human-readable description of the whole purchase.
    170       summary: string;
    171 
    172       // Map from IETF BCP 47 language tags to localized summaries.
    173       summary_i18n?: { [lang_tag: string]: string };
    174 
    175       // Unique identifier for the order. Only characters
    176       // allowed are "A-Za-z0-9" and ".:_-".
    177       // Must be unique within a merchant instance.
    178       // For merchants that do not store proposals in their DB
    179       // before the customer paid for them, the ``order_id`` can be used
    180       // by the frontend to restore a proposal from the information
    181       // encoded in it (such as a short product identifier and timestamp).
    182       order_id?: string;
    183 
    184       // URL where the same contract could be ordered again (if
    185       // available). Returned also at the public order endpoint
    186       // for people other than the actual buyer (hence public,
    187       // in case order IDs are guessable).
    188       public_reorder_url?: string;
    189 
    190       // See documentation of ``fulfillment_url`` field in `ContractTerms`.
    191       // Either fulfillment_url or fulfillment_message must be specified.
    192       // When creating an order, the fulfillment URL can
    193       // contain ``${ORDER_ID}`` which will be substituted with the
    194       // order ID of the newly created order.
    195       fulfillment_url?: string;
    196 
    197       // See documentation of ``fulfillment_message`` in `ContractTerms`.
    198       // Either ``fulfillment_url`` or ``fulfillment_message`` must be specified.
    199       fulfillment_message?: string;
    200 
    201       // Map from IETF BCP 47 language tags to localized fulfillment
    202       // messages.
    203       fulfillment_message_i18n?: { [lang_tag: string]: string };
    204 
    205       // Minimum age the buyer must have to buy.
    206       minimum_age?: Integer;
    207 
    208       // List of products that are part of the purchase.
    209       products?: ProductSold[];
    210 
    211       // Time when this contract was generated. If null, defaults to current
    212       // time of merchant backend.
    213       timestamp?: Timestamp;
    214 
    215       // After this deadline has passed, no refunds will be accepted.
    216       // Overrides deadline calculated from ``refund_delay`` in
    217       // ``PostOrderRequest``.
    218       // A value of "never" is not allowed.
    219       refund_deadline?: Timestamp;
    220 
    221       // After this deadline, the merchant won't accept payments for the contract.
    222       // Overrides deadline calculated from default pay delay configured in
    223       // merchant backend.
    224       // A value of "never" is not allowed.
    225       pay_deadline?: Timestamp;
    226 
    227       // Transfer deadline for the exchange. Must be in the deposit permissions
    228       // of coins used to pay for this order.
    229       // Overrides deadline calculated from default wire transfer delay
    230       // configured in merchant backend. Must be after refund deadline.
    231       // A value of "never" is not allowed.
    232       wire_transfer_deadline?: Timestamp;
    233 
    234       // Base URL of the (public!) merchant backend API.
    235       // Must be an absolute URL that ends with a slash.
    236       // Defaults to the base URL this request was made to.
    237       merchant_base_url?: string;
    238 
    239       // Delivery location for (all!) products.
    240       delivery_location?: Location;
    241 
    242       // Time indicating when the order should be delivered.
    243       // May be overwritten by individual products.
    244       // Must be in the future.
    245       delivery_date?: Timestamp;
    246 
    247       // See documentation of ``auto_refund`` in ``ContractTerms``.
    248       // Specifies for how long the wallet should try to get an
    249       // automatic refund for the purchase.
    250       auto_refund?: RelativeTime;
    251 
    252       // Extra data that is only interpreted by the merchant frontend.
    253       // Useful when the merchant needs to store extra information on a
    254       // contract without storing it separately in their database.
    255       // Must really be an Object (not a string, integer, float or array).
    256       extra?: Object;
    257 
    258       // Money pot to increment for whatever order payment amount
    259       // is not yet assigned to a pot via the ``ProductSold``.
    260       // Not useful to wallets, only for
    261       // merchant-internal accounting.
    262       // Since protocol **v25**.
    263       order_default_money_pot?: Integer;
    264 
    265     }
    266 
    267 
    268   The `OrderChoice` object describes a possible choice within an order. The
    269   choice is done by the wallet and consists of in- and outputs. In the example
    270   of buying an article, the merchant could present the customer with the
    271   choice to use a valid subscription token or pay using a gift
    272   voucher. Available since protocol **v21**.
    273 
    274   .. ts:def:: OrderChoice
    275 
    276     interface OrderChoice {
    277       // Total price for the choice. The exchange will subtract deposit
    278       // fees from that amount before transferring it to the merchant.
    279       amount: Amount;
    280 
    281       // Optional tip amount. Must match the currency of ``amount``.
    282       // Since protocol **v25**.
    283       tip?: Amount;
    284 
    285       // Human readable description of the semantics of the choice
    286       // within the contract to be shown to the user at payment.
    287       description?: string;
    288 
    289       // Map from IETF 47 language tags to localized descriptions.
    290       description_i18n?: { [lang_tag: string]: string };
    291 
    292       // Inputs that must be provided by the customer, if this choice is selected.
    293       // Defaults to empty array if not specified.
    294       inputs?: OrderInput[];
    295 
    296       // Outputs provided by the merchant, if this choice is selected.
    297       // Defaults to empty array if not specified.
    298       outputs?: OrderOutput[];
    299 
    300       // Maximum total deposit fee accepted by the merchant for this contract.
    301       // Overrides defaults of the merchant instance.
    302       max_fee?: Amount;
    303     }
    304 
    305   .. ts:def:: OrderInput
    306 
    307     // For now, only token inputs are supported.
    308     type OrderInput = OrderInputToken;
    309 
    310   .. ts:def:: OrderInputToken
    311 
    312     interface OrderInputToken {
    313 
    314       // Token input.
    315       type: "token";
    316 
    317       // Token family slug as configured in the merchant backend. Slug is unique
    318       // across all configured tokens of a merchant.
    319       token_family_slug: string;
    320 
    321       // How many units of the input are required.
    322       // Defaults to 1 if not specified. Output with count == 0 are ignored by
    323       // the merchant backend.
    324       count?: Integer;
    325 
    326     }
    327 
    328   .. ts:def:: OrderOutput
    329 
    330     type OrderOutput = OrderOutputToken | OrderOutputTaxReceipt;
    331 
    332   .. ts:def:: OrderOutputToken
    333 
    334     interface OrderOutputToken {
    335 
    336       // Token output.
    337       type: "token";
    338 
    339       // Token family slug as configured in the merchant backend. Slug is unique
    340       // across all configured tokens of a merchant.
    341       token_family_slug: string;
    342 
    343       // How many units of the output are issued by the merchant.
    344       // Defaults to 1 if not specified. Output with count == 0 are ignored by
    345       // the merchant backend.
    346       count?: Integer;
    347 
    348       // When should the output token be valid. Can be specified if the
    349       // desired validity period should be in the future (like selling
    350       // a subscription for the next month). Optional. If not given,
    351       // the validity is supposed to be "now" (time of order creation).
    352       valid_at?: Timestamp;
    353 
    354     }
    355 
    356   .. ts:def:: OrderOutputTaxReceipt
    357 
    358     interface OrderOutputTaxReceipt {
    359 
    360       // Tax receipt output.
    361       type: "tax-receipt";
    362 
    363     }
    364 
    365   The following `MinimalInventoryProduct` can be provided if the parts of the
    366   order are inventory-based, that is if the `PostOrderRequest` uses
    367   ``inventory_products``. For such products, which must be in the backend's inventory,
    368   the backend can automatically fill in the amount and other details about
    369   the product that are known to it from its ``products`` table.
    370   Note that the ``inventory_products`` will be appended to the
    371   list of ``products`` that the frontend already put into the ``order``.
    372   So if the frontend can sell additional non-inventory products together
    373   with ``inventory_products``.  Note that the backend will NOT update
    374   the ``amount`` of the ``order``, so the frontend must already have calculated
    375   the total price --- including the ``inventory_products``.
    376 
    377   .. ts:def:: MinimalInventoryProduct
    378 
    379     // Note that if the frontend does give details beyond these,
    380     // it will override those details (including price or taxes)
    381     // that the backend would otherwise fill in via the inventory.
    382     interface MinimalInventoryProduct {
    383 
    384       // Which product is requested (here mandatory!).
    385       product_id: string;
    386 
    387       // Legacy integer quantity.
    388       // Deprecated since **v25**;
    389       // defaults to 1 if both ``quantity`` and ``unit_quantity`` are absent.
    390       quantity?: Integer;
    391 
    392       // Preferred quantity string using "<integer>[.<fraction>]" syntax.
    393       // @since **v25**;
    394       unit_quantity?: string
    395 
    396       // Money pot to use for this product, overrides value from
    397       // the inventory if given.
    398       // Since **v25**.
    399       product_money_pot?: Integer;
    400 
    401     }
    402 
    403   Supply either ``quantity`` or ``unit_quantity`` when referencing inventory products. If both are
    404   missing the backend assumes a quantity of one. ``unit_quantity`` follows the same decimal-string
    405   rules as ``unit_total_stock``.
    406 
    407   .. ts:def:: PostOrderResponse
    408 
    409     interface PostOrderResponse {
    410       // Order ID of the response that was just created.
    411       order_id: string;
    412 
    413       // Deadline when the offer expires; the customer must pay before.
    414       // @since protocol **v21**.
    415       pay_deadline: Timestamp;
    416 
    417       // Token that authorizes the wallet to claim the order.
    418       // Provided only if "create_token" was set to 'true'
    419       // in the request.
    420       token?: ClaimToken;
    421     }
    422 
    423   .. ts:def:: OutOfStockResponse
    424 
    425     interface OutOfStockResponse {
    426 
    427       // Product ID of an out-of-stock item.
    428       product_id: string;
    429 
    430       // Legacy integer quantity requested. Deprecated; see ``unit_requested_quantity``.
    431       requested_quantity: Integer;
    432 
    433       // Requested quantity using "<integer>[.<fraction>]" syntax with up to six fractional digits.
    434       unit_requested_quantity: string;
    435 
    436       // Legacy integer availability (must be below ``requested_quantity``).
    437       available_quantity: Integer;
    438 
    439       // Available quantity using "<integer>[.<fraction>]" syntax with up to six fractional digits.
    440       unit_available_quantity: string;
    441 
    442       // When do we expect the product to be again in stock?
    443       // Optional, not given if unknown.
    444       restock_expected?: Timestamp;
    445     }
    446 
    447 
    448   .. ts:def:: OrderRefusedErrorDetailResponse
    449 
    450     interface OrderRefusedErrorDetailResponse {
    451 
    452       // Numeric `error code <error-codes>` unique to the condition.
    453       // Will be MERCHANT_PRIVATE_POST_ORDERS_AMOUNT_EXCEEDS_LEGAL_LIMITS).
    454       code: ErrorCode;
    455 
    456       // Human-readable description of the error, i.e. "missing parameter", "commitment violation", ...
    457       // Should give a human-readable hint about the error's nature. Optional, may change without notice!
    458       hint?: string;
    459 
    460       // Detail about why a specific exchange was rejected.
    461       // Note that an exchange that was allowed is not listed.
    462       // It is possible that no exchanges were rejected (in which
    463       // case this array would be empty) and still the operation
    464       // failed because the total of the allowed amounts per
    465       // exchange ended up below the order total. Thus, that
    466       // is ultimately always the cause here (as per the code),
    467       // but the *other* reasons why exchanges might have been
    468       // rejected could be enlightening to the user and are
    469       // thus provided here.
    470       exchange_rejections: ExchangeRejectionDetail;
    471     }
    472 
    473   .. ts:def:: ExchangeRejectionDetail
    474 
    475     interface ExchangeRejectionDetail {
    476 
    477       // Base URL of the rejected exchange
    478       exchange_url: string;
    479 
    480       // Numeric `error code <error-codes>` unique to why
    481       // this exchange was not acceptable.
    482       // Can be MERCHANT_GENERIC_CURRENCY_MISMATCH,
    483       // MERCHANT_POST_ORDERS_ID_PAY_EXCHANGE_LEGALLY_REFUSED
    484       // (zero deposit limit, likely KYC required),
    485       // MERCHANT_GENERIC_EXCHANGE_KEYS_FAILURE
    486       // (we failed to download /keys from the exchange),
    487       // MERCHANT_POST_ORDERS_ID_PAY_WIRE_METHOD_UNSUPPORTED
    488       // (none of our bank accounts has a compatible wire method)
    489       code: ErrorCode;
    490 
    491       // Human-readable description of the error.
    492       // Should give a human-readable hint about the error's nature.
    493       // Optional, may change without notice!
    494       hint?: string;
    495 
    496     }