taler-docs

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

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";