taler-docs

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

post-private-orders.rst (19093B)


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