post-private-orders.rst (10517B)
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`` (see :ref:`Scopes <merchant-api-scopes>`) 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 Returned with ``TALER_EC_GENERIC_PARAMETER_MALFORMED``, 39 ``TALER_EC_GENERIC_PARAMETER_MISSING``, 40 ``TALER_EC_GENERIC_JSON_INVALID``, 41 ``TALER_EC_GENERIC_VERSION_MALFORMED``, 42 ``TALER_EC_MERCHANT_PRIVATE_POST_ORDERS_PROPOSAL_PARSE_ERROR``, 43 ``TALER_EC_MERCHANT_PRIVATE_POST_ORDERS_PAY_DEADLINE_IN_PAST``, 44 ``TALER_EC_MERCHANT_PRIVATE_POST_ORDERS_DELIVERY_DATE_IN_PAST``, 45 ``TALER_EC_MERCHANT_PRIVATE_POST_ORDERS_REFUND_DEADLINE_IN_PAST``, 46 ``TALER_EC_MERCHANT_PRIVATE_POST_ORDERS_WIRE_DEADLINE_IS_NEVER`` or 47 ``TALER_EC_MERCHANT_PRIVATE_POST_ORDERS_REFUND_AFTER_WIRE_DEADLINE``. 48 :http:statuscode:`404 Not found`: 49 Possible reasons are: 50 51 (1) The order given used products from the inventory, but those were 52 not found in the inventory. 53 (2) The merchant instance is unknown (including possibly the instance 54 being not configured for new orders). 55 (3) The wire method specified is not supported by the backend. 56 (4) An OTP device ID was specified and is unknown. 57 58 Returned with ``TALER_EC_MERCHANT_GENERIC_PRODUCT_UNKNOWN``, 59 ``TALER_EC_MERCHANT_GENERIC_OTP_DEVICE_UNKNOWN``, 60 ``TALER_EC_MERCHANT_GENERIC_MONEY_POT_UNKNOWN``, 61 ``TALER_EC_MERCHANT_PRIVATE_POST_ORDERS_INSTANCE_CONFIGURATION_LACKS_WIRE`` or 62 ``TALER_EC_MERCHANT_PRIVATE_POST_ORDERS_TOKEN_FAMILY_SLUG_UNKNOWN``. 63 :http:statuscode:`409 Conflict`: 64 A different proposal already exists under the specified order ID, 65 or the requested currency is not supported by this backend. 66 Returned with ``TALER_EC_MERCHANT_PRIVATE_POST_ORDERS_ALREADY_EXISTS``, 67 ``TALER_EC_MERCHANT_PRIVATE_POST_ORDERS_NO_EXCHANGES_FOR_WIRE_METHOD`` or 68 ``TALER_EC_MERCHANT_PRIVATE_POST_ORDERS_NO_EXCHANGE_FOR_CURRENCY``. 69 :http:statuscode:`410 Gone`: 70 The order given used products from the inventory that are out of stock. 71 The response is a :ts:type:`OutOfStockResponse`. 72 :http:statuscode:`451 Unavailable for Legal Reasons`: 73 The order could not be created because of legal 74 reasons, specifically no exchange would accept 75 a payment at this time because we have not yet 76 satisfied the respective legal requirements. 77 The :ref:`KYC status <merchantkycstatus>` API 78 can be used to determine details about how to 79 proceed with the KYC process. 80 Since **v25**, the body is an 81 `OrderRefusedErrorDetailResponse` with an error 82 code of ``TALER_EC_MERCHANT_PRIVATE_POST_ORDERS_AMOUNT_EXCEEDS_LEGAL_LIMITS``. 83 :http:statuscode:`500 Internal Server Error`: 84 The server experienced an internal failure. 85 Returned with ``TALER_EC_GENERIC_DB_STORE_FAILED``, 86 ``TALER_EC_GENERIC_DB_FETCH_FAILED``, 87 ``TALER_EC_GENERIC_DB_COMMIT_FAILED``, 88 ``TALER_EC_GENERIC_DB_SOFT_FAILURE``, 89 ``TALER_EC_GENERIC_FAILED_COMPUTE_JSON_HASH``, 90 ``TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE``, 91 ``TALER_EC_GENERIC_ALLOCATION_FAILURE``, 92 ``TALER_EC_MERCHANT_PRIVATE_POST_ORDERS_NO_LOCALTIME``, 93 ``TALER_EC_MERCHANT_GENERIC_EXCHANGE_KEYS_FAILURE`` or 94 ``TALER_EC_MERCHANT_GENERIC_CURRENCY_MISMATCH``. 95 96 **Details:** 97 98 .. ts:def:: PostOrderRequest 99 100 interface PostOrderRequest { 101 // The order must at least contain the minimal 102 // order detail, but can override all. 103 order: Order; 104 105 // If set, the backend will then set the refund deadline to the 106 // payment deadline plus the specified delay. 107 // If it's not set, the default value of the backend might be 108 // used. Note that both this value and the backend default 109 // will be ignored if ``refund_deadline`` is set in ``order`` 110 // as the ``refund_deadline`` takes precedence. 111 // A value of "forever" is not allowed. 112 refund_delay?: RelativeTime; 113 114 // Specifies the payment target preferred by the client. Can be used 115 // to select among the various (active) wire methods supported by the instance. 116 payment_target?: string; 117 118 // The session for which the payment is made (or replayed). 119 // Only set for session-based payments. The empty session ID 120 // is treated like the field being absent. 121 // Since protocol **v6**. 122 session_id?: SessionID; 123 124 // Specifies that some products are to be included in the 125 // order from the inventory. For these inventory management 126 // is performed (so the products must be in stock) and 127 // details are completed from the product data of the backend. 128 inventory_products?: MinimalInventoryProduct[]; 129 130 // Specifies a lock identifier that was used to 131 // lock a product in the inventory. Only useful if 132 // ``inventory_products`` is set. Used in case a frontend 133 // reserved quantities of the individual products while 134 // the shopping cart was being built. Multiple UUIDs can 135 // be used in case different UUIDs were used for different 136 // products (i.e. in case the user started with multiple 137 // shopping sessions that were combined during checkout). 138 lock_uuids?: string[]; 139 140 // Should a token for claiming the order be generated? 141 // False can make sense if the ORDER_ID is sufficiently 142 // high entropy to prevent adversarial claims (like it is 143 // if the backend auto-generates one). Default is 'true'. 144 // Note: This is NOT related to tokens used for subscriptins or discounts. 145 create_token?: boolean; 146 147 // OTP device ID to associate with the order. 148 // This parameter is optional. 149 otp_id?: Slug; 150 151 } 152 153 .. ts:def:: PostOrderResponse 154 155 interface PostOrderResponse { 156 // Order ID of the response that was just created. 157 order_id: Slug; 158 159 // Deadline when the offer expires; the customer must pay before. 160 // @since protocol **v21**. 161 pay_deadline: Timestamp; 162 163 // Token that authorizes the wallet to claim the order. 164 // Provided only if "create_token" was set to 'true' 165 // in the request. 166 token?: ClaimToken; 167 } 168 169 .. ts:def:: OutOfStockResponse 170 171 interface OutOfStockResponse { 172 173 // Product ID of an out-of-stock item. 174 product_id: Slug; 175 176 // Legacy integer quantity requested. Deprecated; see ``unit_requested_quantity``. 177 requested_quantity: Integer; 178 179 // Requested quantity using "<integer>[.<fraction>]" syntax with up to six fractional digits. 180 unit_requested_quantity: string; 181 182 // Legacy integer availability (must be below ``requested_quantity``). 183 // This is the quantity actually available for new orders: it excludes 184 // units already sold or lost as well as units currently reserved by 185 // locks (shopping carts and unpaid orders). 186 available_quantity: Integer; 187 188 // Available quantity using "<integer>[.<fraction>]" syntax with up to six fractional digits. 189 // Like ``available_quantity``, this excludes units reserved by locks. 190 unit_available_quantity: string; 191 192 // When do we expect the product to be again in stock? 193 // Optional, not given if unknown. 194 restock_expected?: Timestamp; 195 } 196 197 198 .. ts:def:: OrderRefusedErrorDetailResponse 199 200 interface OrderRefusedErrorDetailResponse { 201 202 // Numeric `error code <error-codes>` unique to the condition. 203 // Will be MERCHANT_PRIVATE_POST_ORDERS_AMOUNT_EXCEEDS_LEGAL_LIMITS). 204 code: ErrorCode; 205 206 // Human-readable description of the error, i.e. "missing parameter", "commitment violation", ... 207 // Should give a human-readable hint about the error's nature. Optional, may change without notice! 208 hint?: string; 209 210 // Detail about why a specific exchange was rejected. 211 // Note that an exchange that was allowed is not listed. 212 // It is possible that no exchanges were rejected (in which 213 // case this array would be empty) and still the operation 214 // failed because the total of the allowed amounts per 215 // exchange ended up below the order total. Thus, that 216 // is ultimately always the cause here (as per the code), 217 // but the *other* reasons why exchanges might have been 218 // rejected could be enlightening to the user and are 219 // thus provided here. 220 exchange_rejections: ExchangeRejectionDetail; 221 } 222 223 .. ts:def:: ExchangeRejectionDetail 224 225 interface ExchangeRejectionDetail { 226 227 // Base URL of the rejected exchange 228 exchange_url: WebURL; 229 230 // Numeric `error code <error-codes>` unique to why 231 // this exchange was not acceptable. 232 // Can be MERCHANT_GENERIC_CURRENCY_MISMATCH, 233 // MERCHANT_POST_ORDERS_ID_PAY_EXCHANGE_LEGALLY_REFUSED 234 // (zero deposit limit, likely KYC required), 235 // MERCHANT_GENERIC_EXCHANGE_KEYS_FAILURE 236 // (we failed to download /keys from the exchange), 237 // MERCHANT_POST_ORDERS_ID_PAY_WIRE_METHOD_UNSUPPORTED 238 // (none of our bank accounts has a compatible wire method) 239 code: ErrorCode; 240 241 // Human-readable description of the error. 242 // Should give a human-readable hint about the error's nature. 243 // Optional, may change without notice! 244 hint?: string; 245 246 }