post-private-orders-ORDER_ID-refund-external.rst (5212B)
1 .. http:post:: [/instances/$INSTANCE]/private/orders/$ORDER_ID/refund-external 2 3 Record a refund that was settled outside of Taler, for example a cash or 4 card return. Unlike Taler refunds, this is a bookkeeping entry only: the 5 point-of-sale or external payment integration performs the actual return of 6 funds, and no wallet pickup step exists or is needed. The recorded entries 7 are exposed through the order status as ``refunds_external``. 8 9 External refunds are available for any *paid* order, including pure Taler 10 orders without ``amount_external``. This is relevant because Taler refunds 11 are constrained by the contract's refund deadline; once it has passed, the 12 amount can only be returned through an external method, which is recorded 13 here. 14 15 The refund channel does not need to match the payment channel. The backend 16 validates external refunds against the order total: the cumulative 17 externally refunded amount must not exceed the full order total (the Taler 18 ``amount`` plus all ``amount_external`` entries) minus the amount already 19 refunded through Taler, and must use the currency of the order. 20 21 Each external refund is identified by an ``id`` chosen by the merchant and 22 unique within the order. Recording a refund under an ``id`` that already 23 exists is *idempotent* if the request body is identical, which makes it safe 24 for a point-of-sale application to retry after a network failure without 25 consuming the refundable amount twice. Reusing an existing ``id`` with a 26 different body is refused as a conflict. 27 28 The identifier is mandatory: a recorded external refund cannot be removed, 29 so a duplicate would permanently consume part of the amount that may still 30 be refunded for the order. 31 32 **Required permission:** ``orders-refund`` (see :ref:`Scopes <merchant-api-scopes>`) 33 34 Since protocol **vMixedPayments**. 35 36 **Request:** 37 38 The request body is an `ExternalRefundRequest` object. 39 40 **Response:** 41 42 :http:statuscode:`200 OK`: 43 The external refund was recorded, or had already been recorded with 44 an identical request body. The response is an 45 `ExternalRefundResponse` object containing the identifier of the 46 refund. 47 :http:statuscode:`400 Bad Request`: 48 The request body is malformed, for example the ``method`` is empty, 49 is ``taler``, contains characters other than ASCII alphanumerics 50 and ``-``, or the ``id`` is empty. 51 Returned with ``TALER_EC_GENERIC_PARAMETER_MALFORMED``. 52 :http:statuscode:`401 Unauthorized`: 53 The request is unauthorized. 54 :http:statuscode:`404 Not found`: 55 The order is unknown to the merchant. 56 Returned with ``TALER_EC_MERCHANT_GENERIC_ORDER_UNKNOWN``. 57 :http:statuscode:`409 Conflict`: 58 The external refund could not be recorded. 59 Returned with 60 ``TALER_EC_MERCHANT_PRIVATE_POST_ORDERS_ID_REFUND_ORDER_UNPAID`` 61 if the order is not paid, 62 ``TALER_EC_MERCHANT_GENERIC_CURRENCY_MISMATCH`` 63 if the refund uses a different currency than the order, or 64 ``TALER_EC_MERCHANT_PRIVATE_POST_ORDERS_ID_REFUND_EXTERNAL_INCONSISTENT_AMOUNT`` 65 if the cumulative external refunds would exceed the order total minus 66 the amount already refunded through Taler, or 67 ``TALER_EC_MERCHANT_PRIVATE_POST_ORDERS_ID_REFUND_EXTERNAL_ALREADY_EXISTS`` 68 if an external refund with the same ``id`` was already recorded for 69 this order with different details. 70 :http:statuscode:`500 Internal Server Error`: 71 The server experienced an internal failure. 72 Returned with ``TALER_EC_GENERIC_DB_START_FAILED``, 73 ``TALER_EC_GENERIC_DB_FETCH_FAILED``, 74 ``TALER_EC_GENERIC_DB_STORE_FAILED``, 75 ``TALER_EC_GENERIC_DB_COMMIT_FAILED``, 76 ``TALER_EC_GENERIC_DB_SOFT_FAILURE``, 77 ``TALER_EC_GENERIC_FAILED_COMPUTE_JSON_HASH`` or 78 ``TALER_EC_MERCHANT_GENERIC_DB_CONTRACT_CONTENT_INVALID``. 79 80 **Details:** 81 82 .. ts:def:: ExternalRefundRequest 83 84 interface ExternalRefundRequest { 85 // Method by which the funds were returned to the customer, 86 // for example "cash" or "card". May differ from the methods used 87 // to pay the order. Must be a stable, non-empty identifier of 88 // ASCII alphanumerics and "-", and must never be "taler". 89 method: string; 90 91 // Identifier of this refund within the order, chosen by the 92 // merchant. Must be non-empty. Re-using an identifier with an 93 // identical request body is idempotent; re-using it with 94 // different details is a conflict. 95 id: string; 96 97 // Optionally, the ``id`` of the ``amount_external`` entry this 98 // refund reverses, when the refund maps to a specific original 99 // payment (for example a card transaction reversal). 100 payment_id?: string; 101 102 // Amount returned to the customer via the external method. 103 // Must use the currency of the order. 104 amount: Amount; 105 106 // Human-readable refund justification, mirroring Taler refunds. 107 reason: string; 108 } 109 110 .. ts:def:: ExternalRefundResponse 111 112 interface ExternalRefundResponse { 113 // Identifier of the recorded external refund within the order, 114 // as given in the request. Can be used to reference the refund 115 // later. 116 refund_id: string; 117 }