104-wire-gateway-management-API.rst (7777B)
1 DD 104: Wire Gateway Management API 2 ################################### 3 4 :Design status: Draft 5 :Implementation status: Not started 6 :DD shepherd: Antoine d'Aligny 7 :Historical contributors: Antoine d'Aligny 8 :First published: 2026-09-18 9 :Last substantive change: 2026-09-18 10 11 Summary 12 ======= 13 14 This design document presents the challenges we currently face when handling 15 transaction failures in wire gateway adapters and proposes a solution for 16 addressing them. 17 18 Motivation 19 ========== 20 21 In the current design and implementations, both incoming and outgoing 22 transactions can fail without administrators being notified or having the 23 ability to take corrective action. 24 25 Requirements 26 ============ 27 28 * The solution must allow administrators to see failures, understand their 29 causes, and possibly fix them. 30 * The solution must be lightweight to implement in wire gateway adapters, as 31 the goal of this API is to provide a thin wrapper around how each 32 implementation works. Common logic that can be extracted into another 33 component should be. 34 35 Proposed Solution 36 ================= 37 38 Terminology 39 ----------- 40 41 * `in_tx`: final incoming transaction 42 * `out_tx`: final outgoing transaction 43 * `talerable_in_tx`: talerable final incoming transaction (RESERVE | KYC | MAP) 44 * `talerable_out_tx`: talerable final outgoing transaction (deposit) 45 * `transfer`: initiated talerable outgoing transaction 46 * `initiated`: initiated outgoing transaction 47 * `bounce`: bounced invalid outgoing transaction 48 49 Current API State 50 ----------------- 51 52 We already have endpoints for querying Talerable transactions: 53 `talerable_in_tx` with `GET /history/incoming` and `talerable_out_tx` with 54 `GET /history/outgoing`. 55 56 We also already have endpoints for querying `transfer` with `GET /transfers` 57 and `GET /transfers/$ROW_ID`. 58 59 What is missing is access to raw (incompled, malformed, etc) transactions, `in_tx` and `out_tx`, as well 60 as initiated and bounced transactions, `initiated` and `bounce`. 61 62 Generic API Design 63 ------------------ 64 65 Each adapter works differently. In most adapters, `transfer` and `bounce` 66 produce an `initiated` operation, while other payment systems, such as 67 Cyclos, provide a proper way to perform a bounce idempotently and have a 68 specific bounce operation. 69 70 Each adapter also has different internal unique identifiers. For example, 71 `libeufin_nexus` uses three of them while `depolymerizer-bitcoin` has a 72 single transaction ID. 73 74 We need an API that can expose enough detail for manual reconciliation while 75 remaining generic enough to reuse the same logic across all adapters. 76 77 For `transfer`, we already have the paginated `GET /transfers` endpoint and 78 the single-entry `GET /transfers/$ROW_ID` endpoint. The problem with this 79 design is that it is not well suited to following the progress of transfers. 80 Transfers do not progress or reach finality in the order in which they are 81 created. 82 83 I propose adding a new status-history endpoint, 84 `GET /transfers/status-history`. This will allow administrators to understand 85 the lifecycle of a transaction and track the progress of all transfers in 86 real time. 87 88 We also need new endpoints for `incoming` and `outgoing` transactions, 89 including paginated and single-entry endpoints, so that administrators can 90 inspect all transactions, including incomplete or invalid ones. This is 91 necessary to understand and debug why an incoming transaction never reaches 92 the Talerable history. 93 94 Finally, we need a way to track both `initiated` and `bounce` transactions 95 using new endpoints providing paginated listings, status histories and 96 single-entry views. 97 98 We could potentially remove all `transfer` endpoints, since transfers are a 99 subset of `initiated` operatuibs. Whether to do so depends on whether the 100 transfer-specific API remains useful as a higher-level abstraction. 101 102 We could also enforce a single `initiated` operation concept, event if underneath 103 bounces works differently. As long as doing this it not too messy for the 104 database layer we should pursue this simplification. 105 106 .. ts:def:: InTx 107 108 interface InTx { 109 // Opaque identifier of the returned record. 110 row_id: SafeUint64; 111 112 // Unstructured implementation specific fields that must be shown. 113 // Contains at least the unique identifiers to be used for manual reconciliation. 114 details: {string: string}; 115 116 // Date of the transaction. 117 date: Timestamp; 118 119 // Amount received before credit_fee. 120 amount?: Amount; 121 122 // Unstructured transaction subject 123 subject?: string; 124 125 // Fee paid by the creditor. 126 // If not null, creditor actually received amount - credit_fee 127 credit_fee?: Amount; 128 129 // Full payto URI to identify the sender of funds. 130 debit_account?: string; 131 132 // ID of the bounce operation if bounced 133 bounce_id?: SafeUint64; 134 } 135 136 .. ts:def:: OutTx 137 138 interface OutTx { 139 // Opaque identifier of the returned record. 140 row_id: SafeUint64; 141 142 // Unstructured implementation specific fields that must be shown. 143 // Contains at least the unique identifiers to be used for manual reconciliation. 144 details: {string: string}; 145 146 // Date of the transaction. 147 date: Timestamp; 148 149 // Amount received before credit_fee. 150 amount?: Amount; 151 152 // Unstructured transaction subject 153 subject?: string; 154 155 // Fee paid by the debtor. 156 // If not null, debtor actually paid amount + debit_fee 157 debit_fee?: Amount; 158 159 // Full payto URI to identify the receiver of funds. 160 credit_account?: string; 161 } 162 163 .. ts:def:: InitiatedTx 164 165 interface InitiatedTx { 166 // Opaque ID of this operation. 167 operation_id: SafeUint64; 168 169 // Amount to transfer. 170 amount: Amount; 171 172 // The recipient's account identifier as a full payto:// URI. 173 credit_account: string; 174 175 // Optional ID of the wire transfer initiation if operation is a transfer 176 transfer_id?: SafeUint64; 177 178 // Optional ID of the bounced incoming transaction if operation is a bounce 179 bounced_id?: SafeUint64; 180 181 // Current status 182 // pending: in progress 183 // transient_failure: has failed but may succeed later 184 // permanent_failure: has failed permanently and will never reach finality 185 // success: has succeeded and reached finality 186 // late_failure: has failed permanently after reaching the success status 187 status: "pending" | "transient_failure" | "permanent_failure" | "success" | "late_failure"; 188 189 // Timestamp that indicates when this status was reached. 190 timestamp: Timestamp; 191 } 192 193 .. ts:def:: InitiatedStatus 194 195 interface InitiatedStatus { 196 // Opaque ID of this operation. 197 operation_id: SafeUint64; 198 199 // Opaque ID of this status, used for pagination. 200 row_id: SafeUint64; 201 202 // pending: in progress 203 // transient_failure: has failed but may succeed later 204 // permanent_failure: has failed permanently and will never reach finality 205 // success: has succeeded and reached finality 206 // late_failure: has failed permanently after reaching the success status 207 status: "pending" | "transient_failure" | "permanent_failure" | "success" | "late_failure"; 208 209 // Optional unstructured messages about the status. Can be used to document the reasons for failure or the state of progress. 210 status_msg?: string; 211 212 // Timestamp that indicates when this status was reached. 213 timestamp: Timestamp; 214 } 215 216 Management logic 217 ---------------- 218 219 On top of this API, we could build a Management SPA to support administrative operations. 220 The UI would show recent failures and track whether someone has reviewed them and made a decision on how to handle them. 221 We could also extend the API with administrative operations, such as manually requesting a retry. 222 223 Test Plan 224 ========= 225 226 227 228 Definition of Done 229 ================== 230 231 Alternatives 232 ============ 233 234 Drawbacks 235 ========= 236 237 Discussion / Q&A 238 ================