confirm-pay.rst (13880B)
1 .. ts:op:: confirmPay 2 3 Confirm a payment that was previously prepared with 4 :ts:op:`preparePayForUriV2`, :ts:op:`preparePayForTemplateV2` or 5 :ts:op:`preparePayForPaivana`. 6 7 The wallet selects the coins (and, for a contract v1 order, the 8 tokens) for the payment and submits it to the merchant. For a 9 contract v1 order, ``choiceIndex`` must refer to one of the choices 10 returned by :ts:op:`getChoicesForPayment`. 11 12 **Request:** 13 14 The ``args`` must be a `ConfirmPayRequest` object. 15 16 **Response:** 17 18 On success, the result is a `ConfirmPayResult` object. 19 20 **Side effects:** 21 22 Confirms the prepared payment: the wallet spends the coins and 23 submits the payment to the merchant over the network. 24 25 **Expected errors:** 26 27 The caller can handle the following errors inline: 28 ``WALLET_PAY_MERCHANT_INSUFFICIENT_BALANCE``, 29 ``WALLET_TRANSACTION_NOT_FOUND``, 30 ``WALLET_REQUEST_TRANSACTION_STATE_UNSUPPORTED``, 31 ``WALLET_CORE_API_BAD_REQUEST``. 32 33 **Details:** 34 35 Unless ``noWait`` is set, the operation waits for the first 36 payment result: when the payment succeeded, the result has type 37 ``done``; when the payment could not be completed (yet), the 38 result has type ``pending`` and carries the last error of the 39 payment. With ``noWait``, the operation returns a ``pending`` 40 result immediately and the payment status is communicated via 41 notifications. 42 43 The ``WALLET_PAY_MERCHANT_INSUFFICIENT_BALANCE`` error carries 44 ``insufficientBalanceDetails`` of type 45 `PaymentInsufficientBalanceDetails` in its error detail. 46 47 .. ts:def:: PaymentInsufficientBalanceDetails 48 49 // Detailed reason for why the wallet's balance is insufficient. 50 // 51 // Current wallet-core versions emit all structured fields. The 52 // legacy-only alternative lets clients continue decoding responses 53 // from older cores without allowing partially populated structured 54 // diagnostics. 55 type PaymentInsufficientBalanceDetails = 56 PaymentInsufficientBalanceCompatibilityDetails & 57 (PaymentInsufficientBalanceStructuredDetails 58 | PaymentInsufficientBalanceLegacyOnly); 59 60 .. ts:def:: PaymentInsufficientBalanceStructuredDetails 61 62 // Structured explanation emitted by current wallet-core versions. 63 interface PaymentInsufficientBalanceStructuredDetails { 64 // Balance in the requested sender scope before payment 65 // restrictions. 66 balance: CoinSelectionBalanceSnapshot; 67 68 // Maximum contribution attainable under the failed request's 69 // actual restrictions and fee policy. For peer payments this is 70 // the maximum at one exchange, since peer payments cannot combine 71 // exchanges. 72 maximumPayableAmount: AmountString; 73 74 // Operation-wide reasons, in deterministic evaluation order. 75 reasons: CoinSelectionFailureReason[]; 76 77 // Detailed analysis for every same-currency exchange known to 78 // the wallet. 79 exchanges: Record<string, CoinSelectionExchangeFailureDiagnostics>; 80 } 81 82 .. ts:def:: CoinSelectionBalanceSnapshot 83 84 // Balance amounts before age, receiver, wire and fee restrictions. 85 interface CoinSelectionBalanceSnapshot { 86 // Balance that the wallet believes it can spend immediately. 87 material: AmountString; 88 89 // Expected effective output of unfinished refresh operations. 90 pendingRefresh: AmountString; 91 92 // Material balance plus pending refresh output. 93 available: AmountString; 94 } 95 96 .. ts:def:: CoinSelectionExchangeFailureDiagnostics 97 98 interface CoinSelectionExchangeFailureDiagnostics { 99 // Balance held at this exchange before payment restrictions. 100 balance: CoinSelectionBalanceSnapshot; 101 102 // Maximum contribution selectable from this exchange for 103 // this request. 104 maximumPayableAmount: AmountString; 105 106 // Exchange-local reasons, in deterministic evaluation order. 107 reasons: CoinSelectionFailureReason[]; 108 } 109 110 .. ts:def:: PaymentInsufficientBalanceCompatibilityDetails 111 112 // Request context and compatibility fields shared by old and current 113 // insufficient-balance responses. Fields marked as deprecated are 114 // compatibility-only and planned for removal after consumers migrate. 115 interface PaymentInsufficientBalanceCompatibilityDetails { 116 // Amount requested by the merchant. 117 amountRequested: AmountString; 118 119 // Wire method for the requested payment, only applicable 120 // for merchant payments. 121 wireMethod?: string | undefined; 122 123 // Hint as to why the balance is insufficient. 124 // 125 // If this hint is not provided, the balance hints of the 126 // individual exchanges should be shown, as the overall reason 127 // might be a combination of the reasons for different exchanges. 128 // 129 // Deprecated: use `reasons`. 130 causeHint?: InsufficientBalanceHint; 131 132 // Balance of type "available". 133 // Deprecated: use `balance.available`. 134 balanceAvailable: AmountString; 135 136 // Balance of type "material". 137 // Deprecated: use `balance.material`. 138 balanceMaterial: AmountString; 139 140 // Balance of type "age-acceptable". 141 // Deprecated: use `reasons` and `exchanges`. 142 balanceAgeAcceptable: AmountString; 143 144 // Balance of type "receiver-acceptable". 145 // Deprecated: use `reasons` and `exchanges`. 146 balanceReceiverAcceptable: AmountString; 147 148 // Balance of type "receiver-exchange-url-acceptable". 149 // Deprecated: use `exchanges[url].reasons`. 150 balanceReceiverExchangeUrlAcceptable: AmountString; 151 152 // Balance of type "receiver-exchange-pub-acceptable". 153 // Deprecated: use `exchanges[url].reasons`. 154 balanceReceiverExchangePubAcceptable: AmountString; 155 156 // Balance of type "receiver-auditor-url-acceptable". 157 // Deprecated: use `exchanges[url].reasons`. 158 balanceReceiverAuditorUrlAcceptable: AmountString; 159 160 // Balance of type "merchant-depositable". 161 // Deprecated: use `maximumPayableAmount` and `reasons`. 162 balanceReceiverDepositable: AmountString; 163 164 // Deprecated: use `maximumPayableAmount` and `reasons`. 165 balanceExchangeDepositable: AmountString; 166 167 // Maximum effective amount that the wallet can spend, 168 // when all fees are paid by the wallet. 169 // Deprecated: use `maximumPayableAmount`. 170 maxEffectiveSpendAmount: AmountString; 171 172 // Deprecated: use `exchanges`. 173 perExchange: { 174 [url: string]: { 175 // Deprecated: use `exchanges[url].balance.available`. 176 balanceAvailable: AmountString; 177 178 // Deprecated: use `exchanges[url].balance.material`. 179 balanceMaterial: AmountString; 180 181 // Deprecated: use `exchanges[url].maximumPayableAmount` 182 // and `exchanges[url].reasons`. 183 balanceExchangeDepositable: AmountString; 184 185 // Deprecated: use `exchanges[url].reasons`. 186 balanceAgeAcceptable: AmountString; 187 188 // Deprecated: use `exchanges[url].reasons`. 189 balanceReceiverAcceptable: AmountString; 190 191 // Deprecated: use `exchanges[url].reasons`. 192 balanceReceiverExchangeUrlAcceptable: AmountString; 193 194 // Deprecated: use `exchanges[url].reasons`. 195 balanceReceiverExchangePubAcceptable: AmountString; 196 197 // Deprecated: use `exchanges[url].reasons`. 198 balanceReceiverAuditorUrlAcceptable: AmountString; 199 200 // Deprecated: use `exchanges[url].maximumPayableAmount`. 201 balanceReceiverDepositable: AmountString; 202 203 // Deprecated: use `exchanges[url].maximumPayableAmount`. 204 maxEffectiveSpendAmount: AmountString; 205 206 // The exchange master public key configured by the merchant 207 // backend differs from the one of the coins stored in 208 // the wallet. 209 // Deprecated: use the receiver-exchange-master-pub-mismatch 210 // reason. 211 exchangeMasterPubMismatch: boolean; 212 213 // Exchange doesn't have global fees configured for the 214 // relevant year, p2p payments aren't possible. 215 // Deprecated: use the exchange-global-fees-unavailable reason. 216 missingGlobalFees: boolean; 217 218 // Hint that UIs should show to explain the insufficient 219 // balance. 220 // Deprecated: use `exchanges[url].reasons`. 221 causeHint?: InsufficientBalanceHint | undefined; 222 }; 223 }; 224 } 225 226 .. ts:def:: PaymentInsufficientBalanceLegacyOnly 227 228 // Alternative emitted by older cores: none of the structured 229 // fields are present. 230 interface PaymentInsufficientBalanceLegacyOnly { 231 balance?: undefined; 232 maximumPayableAmount?: undefined; 233 reasons?: undefined; 234 exchanges?: undefined; 235 } 236 237 .. ts:def:: CoinSelectionFailureReason 238 239 // Machine-readable reasons that prevented a requested coin 240 // selection. Unlike `InsufficientBalanceHint`, these values are 241 // exhaustive and can be reported together. Consumers must branch 242 // on the discriminator instead of assuming that the first entry 243 // is the only cause. 244 type CoinSelectionFailureReason = 245 | { 246 type: CoinSelectionFailureReasonType.AvailableBalanceInsufficient; 247 amountAvailable: AmountString; 248 } 249 | { 250 type: CoinSelectionFailureReasonType.PendingRefresh; 251 amountPendingRefresh: AmountString; 252 } 253 | { 254 type: CoinSelectionFailureReasonType.MinimumAge; 255 requiredMinimumAge: number; 256 amountAgeAcceptable: AmountString; 257 } 258 | { 259 type: CoinSelectionFailureReasonType.ScopeRestricted; 260 scopeInfo: ScopeInfo; 261 } 262 | { type: CoinSelectionFailureReasonType.ReceiverNotAccepted } 263 | { 264 type: CoinSelectionFailureReasonType.ReceiverExchangeMasterPubMismatch; 265 walletMasterPub: string; 266 receiverMasterPubs: string[]; 267 } 268 | { 269 type: CoinSelectionFailureReasonType.WireMethodUnsupported; 270 wireMethod: string; 271 } 272 | { 273 type: CoinSelectionFailureReasonType.WireFeeUnavailable; 274 wireMethod: string; 275 } 276 | { 277 type: CoinSelectionFailureReasonType.DepositAccountRestricted; 278 wireMethod: string; 279 accountRestrictions: Record<string, AccountRestriction[]>; 280 } 281 | { type: CoinSelectionFailureReasonType.ExchangeGlobalFeesUnavailable } 282 | { 283 type: CoinSelectionFailureReasonType.FeesNotCovered; 284 maximumPayableAmount: AmountString; 285 } 286 | { 287 type: CoinSelectionFailureReasonType.BalanceFragmented; 288 combinedMaximumPayableAmount: AmountString; 289 } 290 | { 291 type: CoinSelectionFailureReasonType.SupersededExchangeMasterPub; 292 amountAffected: AmountString; 293 } 294 | { type: CoinSelectionFailureReasonType.SelectionFailed }; 295 296 .. ts:def:: CoinSelectionFailureReasonType 297 298 type CoinSelectionFailureReasonType = 299 | "available-balance-insufficient" 300 | "pending-refresh" 301 | "minimum-age" 302 | "scope-restricted" 303 | "receiver-not-accepted" 304 | "receiver-exchange-master-pub-mismatch" 305 | "wire-method-unsupported" 306 | "wire-fee-unavailable" 307 | "deposit-account-restricted" 308 | "exchange-global-fees-unavailable" 309 | "fees-not-covered" 310 | "balance-fragmented" 311 | "superseded-exchange-master-pub" 312 | "selection-failed"; 313 314 .. ts:def:: InsufficientBalanceHint 315 316 // Deprecated: use `CoinSelectionFailureReason` instead. 317 type InsufficientBalanceHint = 318 // Merchant doesn't accept money from exchange(s) that the 319 // wallet supports. 320 | "merchant-accept-insufficient" 321 // Merchant accepts funds from a matching exchange, but the funds 322 // can't be deposited with the wire method. 323 | "merchant-deposit-insufficient" 324 // While in principle the balance is sufficient, the age 325 // restriction on coins causes the spendable balance to be 326 // insufficient. 327 | "age-restricted" 328 // Wallet has enough available funds, but the material funds are 329 // insufficient. Usually because there is a pending refresh 330 // operation. 331 | "wallet-balance-material-insufficient" 332 // The wallet simply doesn't have enough available funds. 333 | "wallet-balance-available-insufficient" 334 // Exchange is missing the global fee configuration, thus fees are 335 // unknown and funds from this exchange can't be used for p2p 336 // payments. 337 | "exchange-missing-global-fees" 338 // Even though the balance looks sufficient for the instructed 339 // amount, the fees can be covered by neither the merchant nor 340 // the remaining wallet balance. 341 | "fees-not-covered"; 342 343 .. ts:def:: ConfirmPayRequest 344 345 interface ConfirmPayRequest { 346 // Transaction identifier of the prepared payment. 347 transactionId: TransactionIdStr; 348 349 // Request that a donation receipt for this payment is collected 350 // via the configured donau, if the selected choice offers a 351 // matching tax-receipt output. 352 useDonau?: boolean; 353 354 // Session ID override for the payment. 355 sessionId?: string; 356 357 // Currently ignored by wallet-core. 358 forcedCoinSel?: ForcedCoinSel; 359 360 // Legacy compatibility option for v1 orders. Ignored: tokens can 361 // only be spent at their issuing merchant, even when this is true. 362 forcedTokenSel?: boolean; 363 364 // Only applies to v1 orders. 365 choiceIndex?: number; 366 367 // Do not wait for the first payment success or error 368 // before returning a response. Instead, status will 369 // be communicated via notifications. 370 // 371 // Will become the default in future versions. 372 noWait?: boolean; 373 } 374 375 .. ts:def:: ConfirmPayResult 376 377 // Result for confirmPay. 378 type ConfirmPayResult = ConfirmPayResultDone | ConfirmPayResultPending; 379 380 .. ts:def:: ConfirmPayResultDone 381 382 interface ConfirmPayResultDone { 383 type: ConfirmPayResultType.Done; 384 contractTerms: MerchantContractTermsV0; 385 transactionId: TransactionIdStr; 386 } 387 388 .. ts:def:: ConfirmPayResultPending 389 390 interface ConfirmPayResultPending { 391 type: ConfirmPayResultType.Pending; 392 transactionId: TransactionIdStr; 393 lastError?: TalerErrorDetail | undefined; 394 } 395 396 .. ts:def:: ConfirmPayResultType 397 398 type ConfirmPayResultType = "done" | "pending";