- confirmPay#
Confirm a payment that was previously prepared with preparePayForUriV2, preparePayForTemplateV2 or preparePayForPaivana.
The wallet selects the coins (and, for a contract v1 order, the tokens) for the payment and submits it to the merchant. For a contract v1 order,
choiceIndexmust refer to one of the choices returned by getChoicesForPayment.Request:
The
argsmust be a ConfirmPayRequest object.Response:
On success, the result is a ConfirmPayResult object.
Side effects:
Confirms the prepared payment: the wallet spends the coins and submits the payment to the merchant over the network.
Expected errors:
The caller can handle the following errors inline:
WALLET_PAY_MERCHANT_INSUFFICIENT_BALANCE,WALLET_TRANSACTION_NOT_FOUND,WALLET_REQUEST_TRANSACTION_STATE_UNSUPPORTED,WALLET_CORE_API_BAD_REQUEST.Details:
Unless
noWaitis set, the operation waits for the first payment result: when the payment succeeded, the result has typedone; when the payment could not be completed (yet), the result has typependingand carries the last error of the payment. WithnoWait, the operation returns apendingresult immediately and the payment status is communicated via notifications.The
WALLET_PAY_MERCHANT_INSUFFICIENT_BALANCEerror carriesinsufficientBalanceDetailsof type PaymentInsufficientBalanceDetails in its error detail.
// Detailed reason for why the wallet's balance is insufficient.
//
// Current wallet-core versions emit all structured fields. The
// legacy-only alternative lets clients continue decoding responses
// from older cores without allowing partially populated structured
// diagnostics.
type PaymentInsufficientBalanceDetails =
PaymentInsufficientBalanceCompatibilityDetails &
(PaymentInsufficientBalanceStructuredDetails
| PaymentInsufficientBalanceLegacyOnly);
// Structured explanation emitted by current wallet-core versions.
interface PaymentInsufficientBalanceStructuredDetails {
// Balance in the requested sender scope before payment
// restrictions.
balance: CoinSelectionBalanceSnapshot;
// Maximum contribution attainable under the failed request's
// actual restrictions and fee policy. For peer payments this is
// the maximum at one exchange, since peer payments cannot combine
// exchanges.
maximumPayableAmount: AmountString;
// Operation-wide reasons, in deterministic evaluation order.
reasons: CoinSelectionFailureReason[];
// Detailed analysis for every same-currency exchange known to
// the wallet.
exchanges: Record<string, CoinSelectionExchangeFailureDiagnostics>;
}
// Balance amounts before age, receiver, wire and fee restrictions.
interface CoinSelectionBalanceSnapshot {
// Balance that the wallet believes it can spend immediately.
material: AmountString;
// Expected effective output of unfinished refresh operations.
pendingRefresh: AmountString;
// Material balance plus pending refresh output.
available: AmountString;
}
interface CoinSelectionExchangeFailureDiagnostics {
// Balance held at this exchange before payment restrictions.
balance: CoinSelectionBalanceSnapshot;
// Maximum contribution selectable from this exchange for
// this request.
maximumPayableAmount: AmountString;
// Exchange-local reasons, in deterministic evaluation order.
reasons: CoinSelectionFailureReason[];
}
// Request context and compatibility fields shared by old and current
// insufficient-balance responses. Fields marked as deprecated are
// compatibility-only and planned for removal after consumers migrate.
interface PaymentInsufficientBalanceCompatibilityDetails {
// Amount requested by the merchant.
amountRequested: AmountString;
// Wire method for the requested payment, only applicable
// for merchant payments.
wireMethod?: string | undefined;
// Hint as to why the balance is insufficient.
//
// If this hint is not provided, the balance hints of the
// individual exchanges should be shown, as the overall reason
// might be a combination of the reasons for different exchanges.
//
// Deprecated: use reasons.
causeHint?: InsufficientBalanceHint;
// Balance of type "available".
// Deprecated: use balance.available.
balanceAvailable: AmountString;
// Balance of type "material".
// Deprecated: use balance.material.
balanceMaterial: AmountString;
// Balance of type "age-acceptable".
// Deprecated: use reasons and exchanges.
balanceAgeAcceptable: AmountString;
// Balance of type "receiver-acceptable".
// Deprecated: use reasons and exchanges.
balanceReceiverAcceptable: AmountString;
// Balance of type "receiver-exchange-url-acceptable".
// Deprecated: use exchanges[url].reasons.
balanceReceiverExchangeUrlAcceptable: AmountString;
// Balance of type "receiver-exchange-pub-acceptable".
// Deprecated: use exchanges[url].reasons.
balanceReceiverExchangePubAcceptable: AmountString;
// Balance of type "receiver-auditor-url-acceptable".
// Deprecated: use exchanges[url].reasons.
balanceReceiverAuditorUrlAcceptable: AmountString;
// Balance of type "merchant-depositable".
// Deprecated: use maximumPayableAmount and reasons.
balanceReceiverDepositable: AmountString;
// Deprecated: use maximumPayableAmount and reasons.
balanceExchangeDepositable: AmountString;
// Maximum effective amount that the wallet can spend,
// when all fees are paid by the wallet.
// Deprecated: use maximumPayableAmount.
maxEffectiveSpendAmount: AmountString;
// Deprecated: use exchanges.
perExchange: {
[url: string]: {
// Deprecated: use exchanges[url].balance.available.
balanceAvailable: AmountString;
// Deprecated: use exchanges[url].balance.material.
balanceMaterial: AmountString;
// Deprecated: use exchanges[url].maximumPayableAmount
// and exchanges[url].reasons.
balanceExchangeDepositable: AmountString;
// Deprecated: use exchanges[url].reasons.
balanceAgeAcceptable: AmountString;
// Deprecated: use exchanges[url].reasons.
balanceReceiverAcceptable: AmountString;
// Deprecated: use exchanges[url].reasons.
balanceReceiverExchangeUrlAcceptable: AmountString;
// Deprecated: use exchanges[url].reasons.
balanceReceiverExchangePubAcceptable: AmountString;
// Deprecated: use exchanges[url].reasons.
balanceReceiverAuditorUrlAcceptable: AmountString;
// Deprecated: use exchanges[url].maximumPayableAmount.
balanceReceiverDepositable: AmountString;
// Deprecated: use exchanges[url].maximumPayableAmount.
maxEffectiveSpendAmount: AmountString;
// The exchange master public key configured by the merchant
// backend differs from the one of the coins stored in
// the wallet.
// Deprecated: use the receiver-exchange-master-pub-mismatch
// reason.
exchangeMasterPubMismatch: boolean;
// Exchange doesn't have global fees configured for the
// relevant year, p2p payments aren't possible.
// Deprecated: use the exchange-global-fees-unavailable reason.
missingGlobalFees: boolean;
// Hint that UIs should show to explain the insufficient
// balance.
// Deprecated: use exchanges[url].reasons.
causeHint?: InsufficientBalanceHint | undefined;
};
};
}
// Alternative emitted by older cores: none of the structured
// fields are present.
interface PaymentInsufficientBalanceLegacyOnly {
balance?: undefined;
maximumPayableAmount?: undefined;
reasons?: undefined;
exchanges?: undefined;
}
// Machine-readable reasons that prevented a requested coin
// selection. Unlike InsufficientBalanceHint, these values are
// exhaustive and can be reported together. Consumers must branch
// on the discriminator instead of assuming that the first entry
// is the only cause.
type CoinSelectionFailureReason =
| {
type: CoinSelectionFailureReasonType.AvailableBalanceInsufficient;
amountAvailable: AmountString;
}
| {
type: CoinSelectionFailureReasonType.PendingRefresh;
amountPendingRefresh: AmountString;
}
| {
type: CoinSelectionFailureReasonType.MinimumAge;
requiredMinimumAge: number;
amountAgeAcceptable: AmountString;
}
| {
type: CoinSelectionFailureReasonType.ScopeRestricted;
scopeInfo: ScopeInfo;
}
| { type: CoinSelectionFailureReasonType.ReceiverNotAccepted }
| {
type: CoinSelectionFailureReasonType.ReceiverExchangeMasterPubMismatch;
walletMasterPub: string;
receiverMasterPubs: string[];
}
| {
type: CoinSelectionFailureReasonType.WireMethodUnsupported;
wireMethod: string;
}
| {
type: CoinSelectionFailureReasonType.WireFeeUnavailable;
wireMethod: string;
}
| {
type: CoinSelectionFailureReasonType.DepositAccountRestricted;
wireMethod: string;
accountRestrictions: Record<string, AccountRestriction[]>;
}
| { type: CoinSelectionFailureReasonType.ExchangeGlobalFeesUnavailable }
| {
type: CoinSelectionFailureReasonType.FeesNotCovered;
maximumPayableAmount: AmountString;
}
| {
type: CoinSelectionFailureReasonType.BalanceFragmented;
combinedMaximumPayableAmount: AmountString;
}
| {
type: CoinSelectionFailureReasonType.SupersededExchangeMasterPub;
amountAffected: AmountString;
}
| { type: CoinSelectionFailureReasonType.SelectionFailed };
type CoinSelectionFailureReasonType =
| "available-balance-insufficient"
| "pending-refresh"
| "minimum-age"
| "scope-restricted"
| "receiver-not-accepted"
| "receiver-exchange-master-pub-mismatch"
| "wire-method-unsupported"
| "wire-fee-unavailable"
| "deposit-account-restricted"
| "exchange-global-fees-unavailable"
| "fees-not-covered"
| "balance-fragmented"
| "superseded-exchange-master-pub"
| "selection-failed";
// Deprecated: use CoinSelectionFailureReason instead.
type InsufficientBalanceHint =
// Merchant doesn't accept money from exchange(s) that the
// wallet supports.
| "merchant-accept-insufficient"
// Merchant accepts funds from a matching exchange, but the funds
// can't be deposited with the wire method.
| "merchant-deposit-insufficient"
// While in principle the balance is sufficient, the age
// restriction on coins causes the spendable balance to be
// insufficient.
| "age-restricted"
// Wallet has enough available funds, but the material funds are
// insufficient. Usually because there is a pending refresh
// operation.
| "wallet-balance-material-insufficient"
// The wallet simply doesn't have enough available funds.
| "wallet-balance-available-insufficient"
// Exchange is missing the global fee configuration, thus fees are
// unknown and funds from this exchange can't be used for p2p
// payments.
| "exchange-missing-global-fees"
// Even though the balance looks sufficient for the instructed
// amount, the fees can be covered by neither the merchant nor
// the remaining wallet balance.
| "fees-not-covered";
interface ConfirmPayRequest {
// Transaction identifier of the prepared payment.
transactionId: TransactionIdStr;
// Request that a donation receipt for this payment is collected
// via the configured donau, if the selected choice offers a
// matching tax-receipt output.
useDonau?: boolean;
// Session ID override for the payment.
sessionId?: string;
// Currently ignored by wallet-core.
forcedCoinSel?: ForcedCoinSel;
// Legacy compatibility option for v1 orders. Ignored: tokens can
// only be spent at their issuing merchant, even when this is true.
forcedTokenSel?: boolean;
// Only applies to v1 orders.
choiceIndex?: number;
// Do not wait for the first payment success or error
// before returning a response. Instead, status will
// be communicated via notifications.
//
// Will become the default in future versions.
noWait?: boolean;
}
// Result for confirmPay.
type ConfirmPayResult = ConfirmPayResultDone | ConfirmPayResultPending;
interface ConfirmPayResultDone {
type: ConfirmPayResultType.Done;
contractTerms: MerchantContractTermsV0;
transactionId: TransactionIdStr;
}
interface ConfirmPayResultPending {
type: ConfirmPayResultType.Pending;
transactionId: TransactionIdStr;
lastError?: TalerErrorDetail | undefined;
}
type ConfirmPayResultType = "done" | "pending";