20.5. Wallet-Core API#
This chapter specifies the API that wallet-core, the reference GNU Taler wallet implementation, exposes to its clients. Clients of this API are the various wallet front-ends (the command-line interface, the WebExtension, the mobile applications and other user interfaces embedding wallet-core), as well as test harnesses.
Unlike most other APIs in GNU Taler, this is not an HTTP REST API: wallet-core runs inside (or alongside) the client application and is driven via an operation-based request/response message protocol. Each request names an operation and carries operation-specific JSON arguments; the response either carries the operation-specific result or a structured error. In the documentation, we use TypeScript syntax to describe the JSON objects, as with the REST APIs.
The reference for all operations and their payloads is the TypeScript source
of wallet-core (packages/taler-wallet-core/src/wallet-api-types.ts and
packages/taler-util/src/types-taler-wallet.ts); a per-operation reference
generated from these sources is also available in the
wallet-core reference.
The glossary defines all specific terms used in this section.
20.5.1. Version History#
The wallet-core API is versioned using the libtool version range
format (current[:revision[:age]]). The currently
implemented protocol version is 10:0:0, reported via the
getVersion operation.
Version history:
v4: first tracked version; adds denomination-loss transactionsv5: requests must use canonicalized base URLsv6: bank-integrated withdrawal via prepare/confirm stepsv7: introduces the transaction finalizing statev8: removes the v1preparePayoperationsv9: payments can be handed off to another wallet (unclaimPayment and reclaimPayment)v10: privacy-scrubbed diagnostics reports (getDiagnostics)
20.5.2. Protocol conventions#
20.5.2.1. Operations#
Every interaction with wallet-core starts with the client sending a
CoreApiRequestEnvelope. The operation field selects the operation,
id is a client-chosen request identifier that is echoed back in the
response (allowing multiple requests to be in flight), and args carries
the operation-specific request payload. Operations that take no arguments
use an empty object (EmptyObject).
interface CoreApiRequestEnvelope {
// Client-chosen request identifier, echoed in the response.
id: string;
// Name of the operation, e.g. "getBalances".
operation: string;
// Operation-specific request payload.
args: unknown;
}
// Placeholder for operations without arguments or without a result.
type EmptyObject = Record<string, never>;
20.5.2.2. Responses and errors#
A request is always answered with exactly one of the following envelopes:
interface CoreApiResponseSuccess {
// Distinguishes the message from errors and notifications.
type: "response";
// Operation that was invoked.
operation: string;
// Request identifier from the corresponding request.
id: string;
// Operation-specific result payload.
result: unknown;
}
interface CoreApiResponseError {
// Distinguishes the message from responses and notifications.
type: "error";
// Operation that was invoked.
operation: string;
// Request identifier from the corresponding request.
id: string;
// Details about the failure.
error: TalerErrorDetail;
}
The error object carries a numeric code from the
error code registry plus optional details. It has the
same structure as the ErrorDetail of the REST APIs (see
Conventions for Taler RESTful APIs), but allows arbitrary additional fields depending on
the error code:
interface TalerErrorDetail {
// Numeric error code unique to the condition.
code: TalerErrorCode;
// When did the error occur.
when?: AbsoluteTime;
// Human-readable description of the error. May change without notice!
hint?: string;
// Additional fields specific to the error code.
[x: string]: unknown;
}
For each operation, this specification lists the expected error codes:
conditions the caller can reasonably react to inline (for example
WALLET_TRANSACTION_NOT_FOUND or
WALLET_PEER_PUSH_PAYMENT_INSUFFICIENT_BALANCE). Any other failure
(network problems, protocol violations, internal errors) is also reported
via the error envelope, but is not listed per operation.
20.5.2.3. Initialization#
initWallet (or
setWalletRunConfig) must be the first
request made to wallet-core; every other operation fails until
initialization has completed. Once the wallet has been shut down via
shutdown, every operation other than
shutdown itself fails with WALLET_CORE_NOT_AVAILABLE until
wallet-core is restarted and initialized again.
20.5.2.4. Notifications#
In addition to responses, wallet-core spontaneously sends notifications
to connected clients, for example when the balance or the state of a
transaction changes. Notifications are not correlated with a request
id. Clients should use them as a trigger to re-query state, not as an
authoritative state transfer. See Notifications for the
list of notification types.
interface CoreApiNotification {
// Distinguishes the message from responses.
type: "notification";
// A WalletNotification object.
payload: unknown;
}
20.5.3. Transports#
The request/response protocol above is transport-agnostic. The following transports are in use:
In-process. Front-ends that link against wallet-core as a library
obtain a WalletCoreApiClient with two methods: call(operation, args)
returns the result or throws on error, and callForResult(operation,
args) returns expected errors (see above) as a Result value instead of
throwing. Notifications are delivered via a registered listener.
Unix-domain socket. taler-wallet-cli can serve the wallet-core API
over a Unix-domain socket (by default ~/.wallet-core.sock), allowing
separate processes — and thus other programming languages — to act as
wallet-core clients. The framing protocol is line-based; JSON messages may
span multiple lines and are wrapped in control lines that start with %:
# On connect, both sides greet each other:
server> %hello-from-server
client> %hello-from-client
# A request is sent as:
client> %request
client> {"operation":"getBalances","id":"req-1","args":{}}
client> %end
# Responses and notifications are both sent as messages:
server> %message
server> {"type":"response","operation":"getBalances","id":"req-1","result":{...}}
server> %end
# Protocol-level errors terminate the connection:
server> %error: invalid message
Browser messaging. The WebExtension front-end talks to wallet-core across the extension’s message channel. The same request, response and notification envelopes are wrapped in a versioned browser RPC message; see Wallet Browser Integration Manual for details.
20.5.4. Operations#
The operations are grouped by topic. Each operation is introduced by a
signature line with the operation’s name, as sent in the operation
field of the CoreApiRequestEnvelope. Unless noted otherwise, the
operation’s args must be an object of the stated request type, and a
successful result is an object of the stated response type.
Operations annotated read-only are pure functions of the wallet’s stored state: they perform no database writes, do not create, cancel or otherwise affect transactions or background tasks, emit no notifications and perform no network requests. All other operations document their side effects explicitly. Operations annotated deprecated are kept for backwards compatibility and should not be used by new clients.
20.5.4.1. Initialization and lifecycle#
- initWallet#
Initialize wallet-core. This must be the first request made to wallet-core; every other operation fails until initialization has completed.
Request:
The request must be an InitRequest object.
Response:
On success, the result is an InitResponse object.
Side effects:
Initializes the wallet: opens the wallet database (using the native sqlite schema for a new, empty database when
config.features.useNativeDbis set, and migrating an existing database to the native sqlite schema whenconfig.features.migrateNativeDbis set), installs the built-in default exchanges (unlessconfig.testing.skipDefaultsis set), appliesconfig.logLevelas the global log level, runs internal data migrations and — on the first initialization only — cleans up failed and leftover claims and deletes ephemeral exchanges, and starts the background task loop (unlessconfig.lazyTaskLoopis set).Details:
Initialization fails with
WALLET_DB_UNAVAILABLEif the wallet database cannot be opened for writing.Calling
initWalletagain after a successful initialization re-initializes the wallet with the new configuration, exactly like setWalletRunConfig. Fields not present inconfigare reset to their defaults.
interface InitRequest {
// Configuration overrides; omitted fields fall back to defaults.
config?: PartialWalletRunConfig;
}
interface PartialWalletRunConfig {
testing?: Partial<WalletRunConfig["testing"]>;
features?: Partial<WalletRunConfig["features"]>;
lazyTaskLoop?: Partial<WalletRunConfig["lazyTaskLoop"]>;
logLevel?: Partial<WalletRunConfig["logLevel"]>;
}
interface WalletRunConfig {
// Unsafe options which should only be used to create
// testing environments.
testing: {
devModeActive: boolean;
insecureTrustExchange: boolean;
preventThrottling: boolean;
skipDefaults: boolean;
emitObservabilityEvents?: boolean;
// Coin selection algorithm to use when spending.
// Defaults to the TALER_WALLET_COINSEL environment variable,
// and to "default" when that is unset.
coinSelectionAlgorithm: CoinSelectionAlgorithm;
};
// Configuration values that may be safe to show to the user.
features: {
allowHttp: boolean;
// Migrate the wallet database to wallet-core's native sqlite
// schema, replacing the IndexedDB emulation. Checked on every
// initialization; off by default.
migrateNativeDb: boolean;
// Use the native sqlite schema when initializing a new, empty
// database; never converts an existing IndexedDB wallet.
useNativeDb: boolean;
};
// Start processing tasks only when explicitly required, even
// after init has been called.
lazyTaskLoop: boolean;
// Global log level.
logLevel: string;
}
// Coin selection algorithm the wallet uses when spending.
// "legacy-2024" is the algorithm shipped in 2024, kept for external
// test suites that pin the coin selections it produces.
type CoinSelectionAlgorithm = "default" | "legacy-2024";
interface InitResponse {
// Version information about the initialized wallet-core.
versionInfo: WalletCoreVersion;
// Database backend used by the initialized wallet.
databaseBackend: WalletDatabaseBackend;
}
// Database backends that wallet-core can run on.
type WalletDatabaseBackend = "indexeddb" | "sqlite";
- setWalletRunConfig#
Change the configuration of wallet-core.
Request:
The request must be an InitRequest object.
Response:
On success, the result is an InitResponse object.
Side effects:
Re-initializes the wallet with the new configuration, with the same effects as initWallet.
Details:
This operation is currently an alias for initWallet: both operations run the same initialization, so
setWalletRunConfigcan also serve as the first request that initializes the wallet. Fields not present inconfigare reset to their defaults.
- getVersionread-only#
Get version information about wallet-core and the protocol versions it supports.
Request:
This operation takes no arguments (an empty object).
Response:
On success, the result is a WalletCoreVersion object.
Details:
The wallet must have been initialized first (see initWallet); before initialization this operation fails with
WALLET_CORE_NOT_AVAILABLE.
interface WalletCoreVersion {
implementationSemver: string;
implementationGitHash: string;
// Wallet-core protocol version supported by this implementation
// of the API ("server" version).
version: string;
exchange: string;
merchant: string;
bankIntegrationApiRange: string;
bankConversionApiRange: string;
corebankApiRange: string;
// Deprecated: the bank API was split into multiple APIs with
// separate versioning.
bank: string;
// Deprecated.
hash: string | undefined;
// Deprecated, will be removed.
devMode: boolean;
}
- shutdown#
Shut down wallet-core.
Request:
This operation takes no arguments (an empty object).
Response:
On success, the result is an empty object.
Side effects:
Stops the background task loop, timers and cryptographic workers and closes the wallet database. Afterwards, every operation other than
shutdownitself fails withWALLET_CORE_NOT_AVAILABLE.Details:
To use the wallet again, wallet-core must be restarted and initWallet called again.
20.5.4.2. Generic request management#
Long-running operations that expose a progressToken can be cancelled or
nudged with the following requests.
- retryProgressTokenNow#
Retry a long-running request now instead of waiting for its scheduled retry delay.
Request:
The request
argsmust be a RetryProgressTokenNowRequest object.Response:
On success, the result is an empty object.
Side effects:
Abandons the remaining exponential-backoff delay of the pending request; the request may restart immediately, causing network activity.
Details:
Long-running operations accept an optional
progressTokenin their request. While such a request keeps failing, wallet-core retries it with exponential backoff and reports each failed attempt via arequest-progress-errornotification, including the delay until the next retry. This operation abandons the remaining delay, so that the next attempt starts immediately. If the progress token is unknown or the request has no retry logic, the operation has no effect.
interface RetryProgressTokenNowRequest {
// Name of the operation that the progress token belongs to.
operation: string;
// Client-chosen progress token passed to the original request.
progressToken: string;
}
- cancelProgressToken#
Cancel the running request associated with a progress token.
Request:
The request
argsmust be a CancelProgressTokenRequest object.Response:
On success, the result is an empty object.
Side effects:
Aborts the in-flight request; the request then fails with error code
WALLET_CORE_REQUEST_CANCELLED.Details:
If the progress token is unknown, the operation has no effect.
interface CancelProgressTokenRequest {
// Name of the operation that the progress token belongs to.
operation: string;
// Client-chosen progress token passed to the original request.
progressToken: string;
}
20.5.4.3. Hints#
Hints inform wallet-core about the state of the host application. They do not query information and never return a meaningful result.
- hintNetworkAvailability#
Inform wallet-core about the host system’s network connectivity.
Request:
The request
argsmust be a HintNetworkAvailabilityRequest object.Response:
On success, the result is an empty object.
Side effects:
Records the host’s network state; on change, background tasks are woken up and may start network activity.
Details:
When the reported availability changes, wallet-core restarts all running background tasks: tasks that are blocked waiting for the network resume when connectivity is back, and tasks notice the outage and wait when it goes away. Reporting the already known state has no effect. Network availability defaults to available, so clients that never send this hint do not block background network activity.
interface HintNetworkAvailabilityRequest {
// Whether the host system currently has network connectivity.
isNetworkAvailable: boolean;
}
- hintPowerState#
Report the host system’s current power source.
Request:
The request
argsmust be a HintPowerStateRequest object.Response:
On success, the result is an empty object.
Side effects:
Records the host’s power state, which affects whether free opportunistic refreshes run. When the power source changes, running background tasks are woken up.
Details:
The power source controls whether wallet-core may refresh coins opportunistically, long before they expire: such early refreshes are only made when they are free of charge, and only on
externalpower. Theunknownpower source never qualifies. When the power source changes, wallet-core restarts all running background tasks.The reported power source is a transient observation: it is discarded when wallet-core restarts, and if no fresh hint arrives within 60 seconds the effective power source falls back to
unknown. Clients should therefore re-report the power state periodically and after any change.
interface HintPowerStateRequest {
// Currently observed power source of the host system.
powerSource: WalletPowerSource;
}
// Power source of the host system, as observed by the client.
type WalletPowerSource = "external" | "battery" | "unknown";
- dismissWalletWarning#
Dismiss a completed renewal notice. Active expiration risks cannot be dismissed.
Request:
The request
argsmust be a DismissWalletWarningRequest object.Response:
On success, the result is an empty object.
Side effects:
Persistently marks a completed renewal notice as dismissed; when a notice was actually dismissed, a
balance-changenotification is emitted.Details:
When wallet-core automatically refreshed coins that were close to expiration, the renewal is reported as a CashRenewalNotice in the
refreshInfo.recoveriesof the affected WalletBalance. Passing the notice’swarningIdto this operation dismisses the notice, so that it is no longer reported. Renewal notices of refresh operations that are still active, as well as unknown warning identifiers, are ignored; the operation still succeeds.
interface DismissWalletWarningRequest {
// Identifier of the wallet warning to dismiss, as found in the
// warningId field of a CashRenewalNotice.
warningId: string;
}
- hintApplicationResumed#
Give wallet-core a kick and restart all pending tasks.
Request:
This operation takes no arguments (an empty object).
Response:
On success, the result is a HintApplicationResumedResponse object.
Side effects:
Restarts all pending tasks and stalled network requests.
Details:
Useful when the host application was suspended and resumed, as active network requests might have stalled. Wallet-core restarts its background tasks and performs a database write and read health check; the outcome of the checks is reported in the response.
interface HintApplicationResumedResponse {
// Did the database write health check succeed?
dbWriteHealthy: boolean;
// Did the database read health check succeed?
dbReadHealthy: boolean;
}
20.5.4.4. Balances#
- getBalancesread-only#
Get current wallet balance.
Balances are reported per scope (ScopeInfo): funds held globally for a currency, at a particular exchange, under a particular auditor or under a superseded exchange master key are reported as separate balances.
Request:
This operation takes no arguments (an empty object).
Response:
On success, the result is a BalancesResponse object.
Details:
Each balance distinguishes three amounts.
availableis the balance available for spending from transactions in their final state, plus amounts expected to become available from pending refreshes.pendingIncomingis the expected positive delta to the available balance once pending operations (such as withdrawals or incoming peer payments) reach the “done” state.pendingOutgoingis the amount currently allocated to spend operations that could still be aborted, in which case part of the amount may be recovered.
interface BalancesResponse {
// Electronic cash balances, per currency scope.
balances: WalletBalance[];
// Does the user have money from an exchange other than demo or test?
haveProdBalance: boolean;
// Summary of donations, per donau/year/currency.
donauSummary?: DonauSummaryItem[];
}
interface WalletBalance {
// DD71 expiry information and conditional
// cost of keeping this balance.
refreshInfo?: WalletRefreshInfo;
// Scope of the funds covered by this balance.
scopeInfo: ScopeInfo;
// Balance available for spending, including amounts
// expected from pending refreshes.
available: AmountString;
// Expected positive delta to the available balance
// from pending operations.
pendingIncoming: AmountString;
// Amount allocated to spend operations that could still be aborted.
pendingOutgoing: AmountString;
// Pending KYC or confirmation steps affecting this balance.
flags: BalanceFlag[];
// Available URLs for pages that list
// where money in this scope can be spent.
shoppingUrls?: string[];
// Are p2p payments disabled for this scope?
disablePeerPayments?: boolean;
// Are wallet deposits disabled for this scope?
disableDirectDeposits?: boolean;
}
interface WalletRefreshInfo {
risks: CashExpirationRisk[];
recoveries: CashRenewalNotice[];
annualCostBound: AnnualRefreshCostBound;
}
interface CashExpirationRisk {
exchangeBaseUrl: string;
exchangeMasterPub: string;
amount: AmountString;
earliestDepositExpiration: TalerProtocolTimestamp;
reason:
| "pending"
| "connectivity"
| "exchange-error"
| "no-replacement"
| "checking"
| "invalid-lifetime";
}
interface CashRenewalNotice {
warningId: string;
exchangeBaseUrl: string;
exchangeMasterPub: string;
amount: AmountString;
oldDepositExpiration: TalerProtocolTimestamp;
newDepositExpiration: TalerProtocolTimestamp;
// Earliest emergency threshold of the renewed coins.
nextRelevantDate: TalerProtocolTimestamp;
}
// Conditional on stable, continuously available compatible
// offerings and timely reveal.
type AnnualRefreshCostBound = {
horizonDays: 365;
projection: "stable-current-offerings";
} & (
| {
status: "available";
amount: AmountString;
}
| {
status: "unavailable";
reasons: string[];
}
);
// Scope of a balance; identifies the trust domain
// the funds belong to.
type ScopeInfo =
| ScopeInfoGlobal
| ScopeInfoExchange
| ScopeInfoAuditor
| ScopeInfoExchangeLegacyKeys;
// Funds held with an exchange that is globally
// trusted for the currency.
type ScopeInfoGlobal = {
type: "global";
currency: string;
};
// Funds held at one particular exchange.
type ScopeInfoExchange = {
type: "exchange";
currency: string;
url: string;
};
// Funds whose denominations are audited by a globally
// trusted auditor.
type ScopeInfoAuditor = {
type: "auditor";
currency: string;
url: string;
};
// Funds issued under a master public key that the exchange has
// since replaced; never pooled with funds under the current key.
type ScopeInfoExchangeLegacyKeys = {
type: "exchange-legacy-keys";
currency: string;
url: string;
// The superseded key the funds were issued under.
masterPub: string;
};
// Flag marking a pending KYC, AML or confirmation step for
// the incoming or outgoing funds of a balance.
type BalanceFlag =
| "incoming-kyc"
| "incoming-aml"
| "incoming-confirmation"
| "outgoing-kyc";
interface DonauSummaryItem {
// Base URL of the donau service.
donauBaseUrl: string;
// Legal domain of the donau service (if available).
legalDomain?: string;
// Year of the donation(s).
year: number;
// Sum of donation receipts received from merchants
// in the applicable year.
amountReceiptsAvailable: AmountString;
// Sum of donation receipts already submitted to the
// donau in the applicable year.
amountReceiptsSubmitted: AmountString;
// Amount of the latest available statement. Missing
// if no statement was requested yet.
amountStatement?: AmountString;
}
- getBalanceDetailread-only#
Get detailed balance information for one currency.
Unlike getBalances, which reports one balance per scope, this operation aggregates the wallet’s funds in the given currency across all exchanges known to the wallet and reports how much of the balance is spendable under progressively stricter criteria.
Request:
The request
argsmust be a GetBalanceDetailRequest object.Response:
On success, the result is a PaymentBalanceDetails object.
Details:
balanceAvailablecovers funds available for spending, including amounts expected from pending refreshes.balanceMaterialis the balance the wallet believes it could spend right now, without waiting for any operations to complete. The remaining balances are subsets of the material balance:balanceAgeAcceptableapplies an age restriction (always zero for this operation), thebalanceReceiver*Acceptablebalances restrict to funds that a receiver accepts based on exchange URL, exchange public key or auditor URL, and the depositable balances additionally require that the funds can be deposited via a supported wire method. Coins signed by a master key that the exchange has since replaced (and not re-advertised) are excluded from all of these balances, as coin selection would never pick them; unlike in getBalances, they are not reported at all here.
interface GetBalanceDetailRequest {
// Currency to compute the balance details for.
currency: string;
}
interface PaymentBalanceDetails {
// Balance of type "available" (see details above).
balanceAvailable: AmountJson;
// Balance of type "material" (see details above).
balanceMaterial: AmountJson;
// Balance of type "age-acceptable" (see details above).
balanceAgeAcceptable: AmountJson;
// Balance of type "receiver-acceptable" (see details above).
// Deprecated, use the balanceReceiver*Acceptable balances instead.
balanceReceiverAcceptable: AmountJson;
// Balance of type "receiver-exchange-url-acceptable".
balanceReceiverExchangeUrlAcceptable: AmountJson;
// Balance of type "receiver-exchange-pub-acceptable".
balanceReceiverExchangePubAcceptable: AmountJson;
// Balance of type "receiver-auditor-url-acceptable".
balanceReceiverAuditorUrlAcceptable: AmountJson;
// Balance of type "receiver-depositable".
balanceReceiverDepositable: AmountJson;
// Balance that is depositable with the exchange, reduced by the
// exchange's debit restrictions and wire fee configuration.
balanceExchangeDepositable: AmountJson;
// Estimated maximum amount that the wallet could pay for,
// under the assumption that the merchant pays absolutely no fees.
maxMerchantEffectiveDepositAmount: AmountJson;
}
20.5.4.5. Transactions#
Every longer-running business process of the wallet (withdrawals, payments, refreshes, peer-to-peer transfers, deposits, …) is represented as a transaction with a state machine. Transaction state changes are reported via transaction-state-transition notifications.
- getTransactionsread-only#
Get the wallet’s transaction list, containing past and pending transactions.
Request:
The request
argsmust be a TransactionsRequest object.Response:
On success, the result is a TransactionsResponse object.
Details:
Refresh transactions are excluded from the result unless
includeRefreshesis set.With the default sort orders (
ascendinganddescending), pending transactions (major statespending,abortinganddialog) are listed before all other transactions; within each group, transactions are sorted by their timestamp, and ties are broken by a fixed transaction-type order. Withstable-ascending, all transactions are sorted purely by ascending timestamp, so pending transactions do not jump around.Filtering by an auditor scope (
scopeInfoof typeauditor) is not supported and fails withWALLET_CORE_API_BAD_REQUEST.
interface TransactionsRequest {
// Return only transactions in the given currency.
// Deprecated: use scopeInfo instead.
currency?: string;
// Return only transactions in the given scope.
scopeInfo?: ScopeInfo;
// Limit results to transactions related to the given search
// string. Currently accepted but not applied by wallet-core.
search?: string;
// Sort order of the transaction items. "ascending" (the
// default) and "descending" sort by timestamp but list pending
// transactions first; "stable-ascending" sorts purely by
// ascending timestamp, with pending transactions in between.
sort?: "ascending" | "descending" | "stable-ascending";
// If true, include all refreshes in the transaction list.
includeRefreshes?: boolean;
// If set, only return transactions matching the state filter.
filterByState?: TransactionStateFilter;
}
// State filter for the transaction list: only transactions in a
// non-final state.
type TransactionStateFilter = "nonfinal";
interface TransactionsResponse {
// List of past and pending transactions matching the request;
// see the respective operation for the sort order.
transactions: Transaction[];
}
type WithdrawalType =
| "taler-bank-integration-api"
| "manual-transfer";
- getTransactionsV2read-only#
Get the wallet’s transaction list, with support for paginated queries.
Request:
The request
argsmust be a GetTransactionsV2Request object.Response:
On success, the result is a TransactionsResponse object.
Details:
Without a
limitand without an offset, all matching transactions are returned in ascending timestamp order.With a positive
limit, at mostlimittransactions are returned in ascending order: without an offset starting at the first transaction, with an offset starting after the offset. With a negativelimit, at most-limittransactions are returned in descending order: without an offset starting at the last transaction, with an offset starting before the offset. Transactions with equal timestamps are ordered by theirtransactionId.If the
offsetTransactionIdno longer exists (for example because the transaction was deleted),offsetTimestampis used as a fallback anchor. If the offset transaction does not exist and nooffsetTimestampis given, the request fails withWALLET_TRANSACTION_NOT_FOUND.Refresh transactions are excluded unless
includeRefreshes(orincludeAll) is set; payments that were superseded by a repurchase are excluded unlessincludeAllis set.
interface GetTransactionsV2Request {
// Return only transactions in the given currency.
currency?: string;
// Return only transactions in the given scope.
scopeInfo?: ScopeInfo;
// If true, include all refreshes in the transaction list.
includeRefreshes?: boolean;
// If true, include transactions that would usually be filtered
// out. Implies includeRefreshes.
includeAll?: boolean;
// Only return transactions before/after this offset.
offsetTransactionId?: TransactionIdStr;
// Only return transactions before/after the transaction with
// this timestamp. Used as a fallback if the
// offsetTransactionId was deleted.
offsetTimestamp?: TalerPreciseTimestamp;
// Number of transactions to return. When positive, results are
// returned in ascending timestamp order (starting at the first
// transaction or after the offset). When negative, results
// are returned in descending timestamp order (starting at the
// last transaction or before the offset).
limit?: number;
// Filter transactions by their state / state category.
// If not specified, all transactions are returned.
// "final": transactions in any final state;
// "nonfinal": transactions in any state but the final states;
// "nonfinal-dialog": nonfinal transactions that require
// confirmation / some choice by the user;
// "nonfinal-approved": nonfinal transactions that need no
// further user approval;
// "done": transactions in the "done" major state.
filterByState?:
| "final"
| "nonfinal"
| "done"
| "nonfinal-approved"
| "nonfinal-dialog";
}
- getTransactionByIdread-only#
Get a single transaction by its identifier.
Request:
The request
argsmust be a TransactionByIdRequest object.Response:
On success, the result is a Transaction object.
Expected errors:
The caller can handle the following errors inline:
WALLET_TRANSACTION_NOT_FOUND,WALLET_CORE_API_BAD_REQUEST.Details:
The
transactionIdmust have the form of a TransactionIdStr; malformed identifiers fail withWALLET_CORE_API_BAD_REQUEST, well-formed but unknown identifiers withWALLET_TRANSACTION_NOT_FOUND.The full contract terms (
contractTerms) are only reported for payment transactions and only whenincludeContractTermsis set.
// A transaction in the wallet's transaction history. The
// type field discriminates the union; all members share the
// fields of TransactionCommon.
type Transaction =
| TransactionWithdrawal
| TransactionPayment
| TransactionRefund
| TransactionRefresh
| TransactionDeposit
| TransactionPeerPullCredit
| TransactionPeerPullDebit
| TransactionPeerPushCredit
| TransactionPeerPushDebit
| TransactionInternalWithdrawal
| TransactionRecoup
| TransactionDenomLoss;
// Opaque, stable identifier of a transaction, of the form
// txn:<type>:<id> where <type> is a TransactionType.
// (The TypeScript source additionally brands this string type;
// the brand only exists at compile time.)
type TransactionIdStr = `txn:${string}:${string}`;
type TransactionType =
| "withdrawal"
| "internal-withdrawal"
| "payment"
| "refund"
| "refresh"
| "deposit"
| "peer-push-debit"
| "peer-push-credit"
| "peer-pull-debit"
| "peer-pull-credit"
| "recoup"
| "denom-loss";
interface TransactionCommon {
// Opaque unique ID for the transaction, used as a starting
// point for paginating queries and for invoking actions on the
// transaction (e.g. deleting it from the history).
transactionId: TransactionIdStr;
// The transaction produced funds under an exchange key set that
// the user subsequently purged from the wallet.
legacy?: boolean;
// Short identifier assigned by this wallet for local,
// human-facing use, of the form #<type>:<localIdent>.
// Intentionally not portable: importing or merging a wallet can
// assign different local identifiers. Clients must use
// transactionId when they need a stable ID. Undefined when
// the wallet backend does not support local IDs.
localTransactionId?: string;
// Type of the transaction; discriminates the Transaction
// union.
type: TransactionType;
// Main timestamp of the transaction.
timestamp: TalerPreciseTimestamp;
// Scopes of this transaction.
scopes: ScopeInfo[];
// Transaction state, as per DD37.
txState: TransactionState;
// Wallet-internal state ID, only used for debugging and
// testing.
stId: number;
// Possible transitions based on the current state.
txActions: TransactionAction[];
// Raw amount of the transaction (exclusive of fees or other
// extra costs).
amountRaw: AmountString;
// Amount shown when the transaction was confirmed, including
// estimated fees. Preserved when execution fails, expires or
// is aborted.
amountEffective: AmountString;
// Settled wallet balance effect, including fees and abort
// recovery. Nonnegative; the transaction type determines
// whether this is a debit or a credit. Absent until the
// transaction and its recovery have settled, or when the amount
// cannot be established for historical records. Ordinary
// merchant refunds remain separate credits. Associated
// refreshes have zero effect.
amountEffectiveFinal?: AmountString;
error?: TalerErrorDetail;
abortReason?: TalerErrorDetail;
failReason?: TalerErrorDetail;
// Location where the user must go to complete KYC; present
// when the transaction's minor state is kyc.
kycUrl?: string;
// KYC payto hash. Useful for testing, not so useful for UIs.
kycPaytoHash?: string;
// KYC access token. Useful for testing, not so useful for UIs.
kycAccessToken?: string;
kycAuthTransferInfo?: KycAuthTransferInfo;
}
interface TransactionState {
// Major state component of the transaction state.
major: TransactionMajorState;
// Minor state component of the transaction.
minor?: TransactionMinorState;
// Whether the wallet is currently actively processing the
// transaction or waiting for a counterparty. Will eventually
// be folded into a new major state.
working?: boolean;
}
type TransactionMajorState =
// No state, only used when reporting transitions into the
// initial state.
| "none"
| "pending"
| "done"
| "aborting"
| "aborted"
| "dialog"
| "finalizing"
// A suspended pending state.
| "suspended"
| "suspended-finalizing"
| "suspended-aborting"
| "failed"
| "expired"
// Only used for notifications, never in the transaction
// history.
| "deleted";
type TransactionMinorState =
| "aborting-bank"
| "accept-refund"
| "auto-refund"
| "balance-kyc"
| "bank"
| "bank-confirm-transfer"
| "bank-register-reserve"
| "check-refund"
| "claim-proposal"
| "completed-by-other-wallet"
| "continued-with-other-wallet"
| "create-purse"
| "delete-purse"
| "deposit"
| "deposit-abort-partial"
| "deposit-abort-recovered"
| "deposit-abort-recovery-failed"
| "deposit-abort-refund-failed"
| "deposit-abort-too-late"
| "exchange"
| "exchange-wait-reserve"
| "kyc-auth"
| "kyc-hard-limit"
| "kyc-init"
| "kyc"
| "merge"
| "paid-by-other"
| "proposed"
| "ready"
| "rebind-session"
| "refresh"
| "refused"
| "repurchase"
| "submit-payment"
| "track"
| "unknown"
| "withdraw"
| "waiting-for-other-wallet"
| "abort";
// Actions the user can request on a transaction in its current
// state; each action corresponds to one of the transaction
// operations.
type TransactionAction =
| "delete"
| "suspend"
| "resume"
| "abort"
| "fail"
| "retry";
interface KycAuthTransferInfo {
// Payto URI of the account that must make the transfer. The
// KYC auth transfer will *not* work if it originates from a
// different account.
debitPaytoUri: string;
// Account public key. Included in the transfer subject for
// some of the transfer options.
accountPub: string;
// Options for making the KYC auth transfer, grouped by exchange
// credit account in the same format used for withdrawals.
transferOptionsExt: WithdrawalExchangeAccountDetails[];
// Options for making the KYC auth transfer payment to the
// exchange. Deprecated: use transferOptionsExt instead.
transferOptions: TransferOption[];
// Validity of the transferOptions, or undefined if they do not
// expire. Deprecated: use the per-account expiry in
// transferOptionsExt instead.
transferExpiry: TalerProtocolTimestamp | undefined;
// Amount that the exchange expects to be deposited. Usually
// the smallest amount that can be transferred via a bank
// transfer. Deprecated: use transferOptions instead.
amount: AmountString;
// Possible target payto URIs. Deprecated: use
// transferOptions instead.
creditPaytoUris: string[];
}
// A withdrawal transaction (either bank-integrated or manual).
interface TransactionWithdrawal extends TransactionCommon {
type: "withdrawal";
// Exchange of the withdrawal.
exchangeBaseUrl: string | undefined;
// Amount that got subtracted from the reserve balance.
amountRaw: AmountString;
// Amount that actually was (or will be) added to the wallet's
// balance.
amountEffective: AmountString;
withdrawalDetails: WithdrawalDetails;
}
// Internal withdrawal operation, only reported on request. Some
// transactions (peer-*-credit) internally do a withdrawal, but
// only the peer-*-credit transaction is reported. The internal
// withdrawal transaction gives access to the details of the
// underlying withdrawal for testing/debugging. It is usually not
// reported, so that the amounts of transactions properly add up.
interface TransactionInternalWithdrawal extends TransactionCommon {
type: "internal-withdrawal";
// Exchange of the withdrawal.
exchangeBaseUrl: string;
// Amount that got subtracted from the reserve balance.
amountRaw: AmountString;
// Amount that actually was (or will be) added to the wallet's
// balance.
amountEffective: AmountString;
withdrawalDetails: WithdrawalDetails;
}
type WithdrawalDetails =
| WithdrawalDetailsForManualTransfer
| WithdrawalDetailsForTalerBankIntegrationApi;
interface WithdrawalDetailsForManualTransfer {
type: "manual-transfer";
// Payto URIs that the exchange supports. Already contains the
// amount and message. Deprecated: in favor of
// exchangeCreditAccountDetails.
exchangePaytoUris: string[];
exchangeCreditAccountDetails?: WithdrawalExchangeAccountDetails[];
// Public key of the reserve.
reservePub: string;
// Is the reserve ready for withdrawal?
reserveIsReady: boolean;
// How long the exchange waits to transfer back funds from a
// reserve.
reserveClosingDelay: TalerProtocolDuration;
}
interface WithdrawalDetailsForTalerBankIntegrationApi {
type: "taler-bank-integration-api";
// True if the bank has confirmed the withdrawal. An
// unconfirmed withdrawal usually requires user input and should
// be highlighted in the UI; see bankConfirmationUrl.
confirmed: boolean;
// If the withdrawal is unconfirmed, this can include a URL for
// user-initiated confirmation.
bankConfirmationUrl?: string;
// Public key of the reserve.
reservePub: string;
// Is the reserve ready for withdrawal?
reserveIsReady: boolean;
// Is the bank transfer for the withdrawal externally
// confirmed?
externalConfirmation?: boolean;
exchangeCreditAccountDetails?: WithdrawalExchangeAccountDetails[];
}
interface TransactionPayment extends TransactionCommon {
type: "payment";
// Merchant instance base URL used to claim the order.
// Available even before the contract terms have been
// downloaded.
merchantBaseUrl: string;
// Public payment URI shown while this wallet waits for another
// wallet to claim an order that it released.
unclaimedPayUri?: TalerUriString;
// Additional information about the payment. Only present if
// the information about the order is already available.
info: OrderShortInfo | undefined;
// Full contract terms. Only included if explicitly requested
// via the includeContractTerms flag of
// getTransactionById.
contractTerms?: MerchantContractTerms;
// Amount that must be paid for the contract.
amountRaw: AmountString;
// Amount that was paid, including deposit, wire and refresh
// fees.
amountEffective: AmountString;
// Amount that has been refunded by the merchant.
totalRefundRaw: AmountString;
// Amount that will be added to the wallet's balance after fees
// and refreshing.
totalRefundEffective: AmountString;
// Amount pending to be picked up.
refundPending: AmountString | undefined;
// Reference to applied refunds.
refunds: RefundInfoShort[];
// Is the wallet currently checking for a refund?
refundQueryActive: boolean;
// PoS confirmation codes, separated by newlines. Only present
// for purchases that support PoS confirmation.
posConfirmation: string | undefined;
// Until when the posConfirmation is valid.
posConfirmationDeadline?: TalerProtocolTimestamp;
// Did we receive the payment via a taler://pay-template/ URI
// and did the URI contain a nfc=1 flag?
posConfirmationViaNfc?: boolean;
// In case this payment transaction was detected as a
// repurchase, the transaction ID of the original payment.
repurchaseTransactionId?: TransactionIdStr;
// If applicable, the choice that the user selected.
choiceIndex?: number;
}
interface OrderShortInfo {
// Order ID, uniquely identifies the order within a merchant
// instance.
orderId: string;
// Hash of the contract terms.
contractTermsHash: string;
// More information about the merchant.
merchant: MerchantInfo;
// Summary of the order, given by the merchant.
summary: string;
// Map from IETF BCP 47 language tags to localized summaries.
summary_i18n?: InternationalizedString;
// URL of the fulfillment, given by the merchant.
fulfillmentUrl?: string;
// Plain text message that should be shown to the user when the
// payment is complete.
fulfillmentMessage?: string;
// Translations of fulfillmentMessage.
fulfillmentMessage_i18n?: InternationalizedString;
}
interface RefundInfoShort {
transactionId: string;
timestamp: TalerProtocolTimestamp;
amountEffective: AmountString;
amountRaw: AmountString;
}
interface TransactionRefund extends TransactionCommon {
// Recovery already included in the unsuccessful payment's
// final cost.
isAbortRecovery?: boolean;
type: "refund";
// Amount that has been refunded by the merchant.
amountRaw: AmountString;
// Amount that will be added to the wallet's balance after fees
// and refreshing.
amountEffective: AmountString;
// ID of the transaction that is refunded.
refundedTransactionId: string;
paymentInfo: RefundPaymentInfo | undefined;
}
// Summary information about the payment that we got a refund
// for.
interface RefundPaymentInfo {
summary: string;
summary_i18n?: InternationalizedString;
// More information about the merchant.
merchant: MerchantInfo;
}
// A transaction shown for refreshes. Only shown for (1)
// refreshes not associated with other transactions and (2)
// refreshes in an error state.
interface TransactionRefresh extends TransactionCommon {
type: "refresh";
refreshReason: RefreshReason;
// Transaction ID that caused this refresh.
originatingTransactionId?: string;
// Always zero for refreshes.
amountRaw: AmountString;
// Fees, i.e. the effective, negative effect of the refresh on
// the balance. Only applicable for stand-alone refreshes, and
// zero for other refreshes where the transaction itself
// accounts for the refresh fee.
amountEffective: AmountString;
refreshInputAmount: AmountString;
refreshOutputAmount: AmountString;
}
// Reason why a coin is being refreshed.
type RefreshReason =
| "manual"
| "pay-merchant"
| "pay-deposit"
| "pay-peer-push"
| "pay-peer-pull"
| "refund"
| "abort-pay"
| "abort-deposit"
| "abort-peer-push-debit"
| "abort-peer-pull-debit"
| "recoup"
| "backup-restored"
| "scheduled";
// Deposit transaction, which effectively sends money from this
// wallet somewhere else.
interface TransactionDeposit extends TransactionCommon {
type: "deposit";
depositGroupId: string;
// Target for the deposit.
targetPaytoUri: string;
// Raw amount that is being deposited.
amountRaw: AmountString;
// Deposit account public key.
accountPub: string;
// Effective amount that is being deposited.
amountEffective: AmountString;
wireTransferDeadline: TalerProtocolTimestamp;
wireTransferProgress: number;
// Did all the deposit requests succeed?
deposited: boolean;
trackingState: Array<DepositTransactionTrackingState>;
}
interface DepositTransactionTrackingState {
// Raw wire transfer identifier of the deposit.
wireTransferId: string;
// When the wire transfer was given to the bank.
timestampExecuted: TalerProtocolTimestamp;
// Total amount transferred for this wtid (including fees).
amountRaw: AmountString;
// Wire fee amount for this exchange.
wireFee: AmountString;
}
// Credit because we were paid for a P2P invoice we created.
interface TransactionPeerPullCredit extends TransactionCommon {
type: "peer-pull-credit";
info: PeerInfoShort;
// Exchange used.
exchangeBaseUrl: string;
// Amount that got subtracted from the reserve balance.
amountRaw: AmountString;
// Amount that actually was (or will be) added to the wallet's
// balance.
amountEffective: AmountString;
// URI to send to the other party. Only available in the right
// state.
talerUri: string | undefined;
}
// Debit because we paid someone's invoice.
interface TransactionPeerPullDebit extends TransactionCommon {
type: "peer-pull-debit";
info: PeerInfoShort;
// Exchange used.
exchangeBaseUrl: string;
amountRaw: AmountString;
amountEffective: AmountString;
}
// We sent money via a P2P payment.
interface TransactionPeerPushDebit extends TransactionCommon {
type: "peer-push-debit";
info: PeerInfoShort;
// Exchange used.
exchangeBaseUrl: string;
// Amount that got subtracted from the reserve balance.
amountRaw: AmountString;
// Amount that actually was (or will be) added to the wallet's
// balance.
amountEffective: AmountString;
// URI to accept the payment. Only present if the transaction
// is in a state where the other party can accept the payment.
talerUri?: string;
}
// We received money via a P2P payment.
interface TransactionPeerPushCredit extends TransactionCommon {
type: "peer-push-credit";
info: PeerInfoShort;
// Exchange used.
exchangeBaseUrl: string;
// Amount that got subtracted from the reserve balance.
amountRaw: AmountString;
// Amount that actually was (or will be) added to the wallet's
// balance.
amountEffective: AmountString;
}
interface PeerInfoShort {
expiration: TalerProtocolTimestamp | undefined;
summary: string | undefined;
iconId: string | undefined;
}
// The exchange revoked a key and the wallet recoups funds.
interface TransactionRecoup extends TransactionCommon {
type: "recoup";
}
// A transaction to indicate financial loss due to denominations
// that became unusable for deposits.
interface TransactionDenomLoss extends TransactionCommon {
type: "denom-loss";
lossEventType: DenomLossEventType;
exchangeBaseUrl: string;
}
type DenomLossEventType =
| "denom-expired"
| "denom-vanished"
| "denom-unoffered"
// The exchange revoked the denomination. A revoked
// denomination also stops being offered, so this must be
// checked before "denom-unoffered" to say what actually
// happened.
| "denom-revoked";
interface TransactionByIdRequest {
transactionId: string;
// If set to true, report the full contract terms in the
// response if the transaction has them.
includeContractTerms?: boolean;
}
- resolveTransactionReferenceread-only#
Resolve a stable transaction ID, a wallet-local identifier, or an external withdrawal reference to a stable transaction ID.
Request:
The request
argsmust be a ResolveTransactionReferenceRequest object.Response:
On success, the result is a ResolveTransactionReferenceResponse object.
Expected errors:
The caller can handle the following errors inline:
WALLET_TRANSACTION_NOT_FOUND,WALLET_CORE_API_BAD_REQUEST.Details:
Three kinds of references are accepted:
a stable transaction ID (TransactionIdStr), which is returned unchanged;
a wallet-local identifier of the form
#<type>:<localIdent>, as reported in the transaction’slocalTransactionIdfield. Local identifiers are deliberately not portable: importing or merging a wallet can assign different local identifiers;an external, bank-generated withdrawal reference (such as an LSD 0006 withdrawal-transfer-result reference) that contains the reserve public key of a withdrawal. The reference must match exactly one withdrawal transaction, otherwise the request fails with
WALLET_TRANSACTION_NOT_FOUND.
interface ResolveTransactionReferenceRequest {
transactionReference: string;
}
interface ResolveTransactionReferenceResponse {
transactionId: TransactionIdStr;
}
- abortTransaction#
Abort a transaction.
Request:
The request
argsmust be an AbortTransactionRequest object.Response:
On success, the result is an empty object.
Side effects:
Transitions the transaction into an aborting state and starts abort processing, which may issue refunds or recover coins (network activity).
Expected errors:
The caller can handle the following errors inline:
WALLET_TRANSACTION_NOT_FOUND,WALLET_TRANSACTION_ACTION_UNSUPPORTED,WALLET_REQUEST_TRANSACTION_STATE_UNSUPPORTED.Details:
For payment transactions, aborting puts the payment into an
abortingstate, in which the wallet recovers the spent coins via a refund where possible before the transaction reaches a final state. Whether a transaction can currently be aborted is advertised in itstxActions.
interface AbortTransactionRequest {
transactionId: TransactionIdStr;
}
- failTransaction#
Mark a transaction as failed, giving up on its ongoing processing.
Request:
The request
argsmust be a FailTransactionRequest object.Response:
On success, the result is an empty object.
Side effects:
Marks an aborting transaction as finally failed, giving up on the ongoing recovery.
Expected errors:
The caller can handle the following errors inline:
WALLET_TRANSACTION_NOT_FOUND,WALLET_TRANSACTION_ACTION_UNSUPPORTED,WALLET_REQUEST_TRANSACTION_STATE_UNSUPPORTED.Details:
This is typically used for transactions in an
abortingstate (for example while recovering an aborted payment via a refund): the user stops waiting for the recovery, and the transaction transitions to the finalfailedstate. The reason is recorded in the transaction’sfailReason. Whether a transaction can currently be failed is advertised in itstxActions.
interface FailTransactionRequest {
transactionId: TransactionIdStr;
}
- suspendTransaction#
Suspend a transaction, stopping any associated network activities while keeping the option of trying again at a later time. This can be useful to save battery power or bandwidth when an operation is expected to take longer, such as a very large withdrawal.
Request:
The request
argsmust be an AbortTransactionRequest object.Response:
On success, the result is an empty object.
Side effects:
Suspends a pending transaction; its processing stops.
Expected errors:
The caller can handle the following errors inline:
WALLET_TRANSACTION_NOT_FOUND,WALLET_TRANSACTION_ACTION_UNSUPPORTED,WALLET_REQUEST_TRANSACTION_STATE_UNSUPPORTED.
- resumeTransaction#
Resume a transaction that was previously suspended with suspendTransaction.
Request:
The request
argsmust be an AbortTransactionRequest object.Response:
On success, the result is an empty object.
Side effects:
Resumes a suspended transaction; its processing restarts, possibly with network activity.
Expected errors:
The caller can handle the following errors inline:
WALLET_TRANSACTION_NOT_FOUND,WALLET_TRANSACTION_ACTION_UNSUPPORTED,WALLET_REQUEST_TRANSACTION_STATE_UNSUPPORTED.
- deleteTransaction#
Permanently delete a transaction from the wallet’s transaction history.
Request:
The request
argsmust be a DeleteTransactionRequest object.Response:
On success, the result is an empty object.
Side effects:
Deletes the transaction from the wallet’s history.
Expected errors:
The caller can handle the following errors inline:
WALLET_TRANSACTION_NOT_FOUND,WALLET_REQUEST_TRANSACTION_STATE_UNSUPPORTED.Details:
Deleting is only possible in states that advertise the
deleteaction (intxActions), typically final or dialog states. Any background task associated with the transaction is stopped.
interface DeleteTransactionRequest {
transactionId: TransactionIdStr;
}
- retryTransaction#
Immediately retry the transaction’s underlying operation by resetting the retry timer of its background task.
Request:
The request
argsmust be a RetryTransactionRequest object.Response:
On success, the result is an empty object.
Side effects:
Immediately retries processing of the transaction; network activity is possible.
Expected errors:
The caller can handle the following errors inline:
WALLET_TRANSACTION_NOT_FOUND,WALLET_REQUEST_TRANSACTION_STATE_UNSUPPORTED.Details:
Retrying is only possible in states that advertise the
retryaction (intxActions); the request does not wait for the retried operation to complete.
interface RetryTransactionRequest {
transactionId: TransactionIdStr;
}
- listAssociatedRefreshes#
List the refresh transactions associated with another transaction.
This operation is declared but not implemented yet: it currently always fails with
GENERIC_FEATURE_NOT_IMPLEMENTED.Request:
The request
argsmust be a ListAssociatedRefreshesRequest object.Response:
On success, the result is a ListAssociatedRefreshesResponse object.
interface ListAssociatedRefreshesRequest {
transactionId: string;
}
interface ListAssociatedRefreshesResponse {
transactionIds: string[];
}
- waitTransactionStateread-only#
Wait until a transaction is in a particular state. The operation blocks until the transaction reaches the requested state, an error occurs, or the timeout expires.
Request:
The request
argsmust be a WaitTransactionStateRequest object.Response:
On success, the result is a WaitTransactionStateResponse object.
Details:
This is a long-polling operation: it returns once the transaction’s state matches
txState, matches one of thebailStates, or (withbailOnError) an error is recorded for the transaction. The response’smatchedfield says which of the two sets of states ended the wait.The
txStateandbailStatesfields are TestingWaitTxStateSpec values: a TransactionStatePattern or a list of patterns (matching when any pattern matches), a wallet-internal numeric state ID, or one of the shorthandsnonpending(any major state other thanpending) andfinal(any final major state). In a pattern,major,minorandworkingaccept the wildcard*; a pattern withoutminoronly matches states that have no minor state, while a pattern withoutworkingmatches regardless of the flag.Without
bailStatesorbailOnError, a transaction that reaches a state it will never leave keeps the caller waiting until thetimeoutexpires; the wait then fails withGENERIC_TIMEOUT.If no transaction with the given
transactionIdexists, the wait fails withWALLET_TRANSACTION_NOT_FOUNDinstead of waiting.When
progressTokenis set, the wait reports request progress notifications (including recorded transaction errors with their retry counter and remaining retry delay) and can be cancelled with cancelProgressToken or nudged with retryProgressTokenNow. Cancellation fails the wait withWALLET_CORE_REQUEST_CANCELLED; it stops only the wait, not the transaction.
interface WaitTransactionStateRequest {
transactionId: TransactionIdStr;
// Receive request progress notifications and control this wait
// via cancelProgressToken/retryProgressTokenNow.
// Cancellation stops only the wait. Retry-now retries the
// transaction if its current state allows it, without
// restarting the wait or extending its timeout. Transaction
// errors are reported with their recorded retry counter and
// remaining delay; without a recorded error retry, the counter
// is zero and the delay is "forever".
progressToken?: string;
// Additional identifier that is used in the logs to easily
// find the status of the particular wait request.
logId?: string;
// After the timeout has passed, give up on waiting for the
// desired state and raise an error instead.
timeout?: DurationUnitSpec;
// If set to true, wait until the desired state is reached
// with an error.
requireError?: boolean;
// State(s) to wait for.
txState: TestingWaitTxStateSpec;
// States that end the wait even though they are not the state
// that was waited for. The response says which of the two
// sets matched. Without this, a transaction that ends up in
// a state it will never leave keeps the caller waiting until
// the timeout.
bailStates?: TestingWaitTxStateSpec;
// End the wait as soon as an error is recorded for the
// transaction. Beware that this includes transient errors of
// retried operations, which are cleared again once the
// operation succeeds.
bailOnError?: boolean;
}
interface WaitTransactionStateResponse {
// Which set of states ended the wait: the requested state or
// one of the bail states.
matched: "target" | "bail";
// State that ended the wait.
txState: TransactionState;
// Wallet-internal state ID, only used for debugging and
// testing.
stId: number;
}
// State(s) to wait for: a plain pattern or a list of patterns
// (matching any of them), a wallet-internal numeric state ID, or
// one of the shorthands for a category of states.
type TestingWaitTxStateSpec =
| TransactionStatePattern
| TransactionStatePattern[]
| number
| "nonpending"
| "final";
interface TransactionStatePattern {
major: TransactionMajorState | TransactionStateWildcard;
minor?: TransactionMinorState | TransactionStateWildcard;
// Required value of the "working" flag of the transaction
// state. A transaction state without the flag counts as
// false. If left undefined, the flag is not taken into
// account when matching, i.e. it behaves like a wildcard.
working?: boolean | TransactionStateWildcard;
}
type TransactionStateWildcard = "*";
// A duration given as a sum of the specified units; used for
// timeouts.
interface DurationUnitSpec {
seconds?: number;
minutes?: number;
hours?: number;
days?: number;
months?: number;
years?: number;
}
20.5.4.6. Withdrawals#
Withdrawal operations bring coins from an exchange into the wallet, either via a bank-integrated flow (the user authorizes the transfer in their banking application) or via a manual wire transfer to the exchange.
- prepareWithdrawExchange#
Prepare for withdrawing via a
taler://withdraw-exchangeURI.The URI names the exchange to withdraw from and may fix an amount. Wallet-core fetches (or updates) the exchange entry, ephemerally adding the exchange to the wallet’s known exchanges if it is not known yet, and checks that the currency of the URI’s amount matches the exchange’s currency.
This is the first step of a manual withdrawal that is initiated on the exchange’s side. The client can then query the fees and other details with getWithdrawalDetailsForAmount and create the withdrawal with acceptManualWithdrawal.
Request:
The request must be a PrepareWithdrawExchangeRequest object.
Response:
On success, the result is a PrepareWithdrawExchangeResponse object.
Side effects:
Fetches (or updates) the exchange entry over the network; if the exchange is not known to the wallet yet, it is ephemerally added to the known exchanges. No withdrawal transaction is created.
Expected errors:
The caller can handle the following errors inline:
WALLET_TALER_URI_MALFORMED,GENERIC_CURRENCY_MISMATCH.
interface PrepareWithdrawExchangeRequest {
// A taler://withdraw-exchange URI.
talerUri: string;
progressToken?: string;
}
interface PrepareWithdrawExchangeResponse {
// Base URL of the exchange that already existed or was
// ephemerally added as an exchange entry to the wallet.
exchangeBaseUrl: string;
// Amount from the taler://withdraw-exchange URI.
// Only present if specified in the URI.
amount?: AmountString;
}
- prepareBankIntegratedWithdrawal#
Prepare a bank-integrated withdrawal operation.
Wallet-core resolves the
taler://withdrawURI against the bank’s bank integration API, obtains the status of the withdrawal operation and creates a withdrawal transaction in a dialog state. If the bank suggests an exchange that is not known to the wallet yet, it is ephemerally added to the wallet’s known exchanges.After the user has reviewed the operation’s details (and selected an amount and an exchange, where the bank allows choosing them), the client confirms the withdrawal with confirmWithdrawal.
Request:
The request must be a PrepareBankIntegratedWithdrawalRequest object.
Response:
On success, the result is a PrepareBankIntegratedWithdrawalResponse object.
Side effects:
Queries the bank’s bank integration API over the network and creates the withdrawal transaction in the wallet database. May also fetch and ephemerally add the exchange suggested by the bank.
Expected errors:
The caller can handle the following errors inline:
WALLET_TALER_URI_MALFORMED.Details:
The operation is idempotent with respect to the URI: calling it again with the same
talerWithdrawUrireturns the existing withdrawal transaction instead of creating a new one. If the bank reports the withdrawal operation as already selected, confirmed or aborted and the wallet has no transaction for it, the request fails withWALLET_WITHDRAWAL_OPERATION_ABORTED_BY_BANK.
interface PrepareBankIntegratedWithdrawalRequest {
talerWithdrawUri: string;
progressToken?: string;
}
interface PrepareBankIntegratedWithdrawalResponse {
// Transaction ID of the withdrawal transaction (newly created or
// already existing for the same URI).
transactionId: TransactionIdStr;
// Details of the bank-side withdrawal operation.
info: WithdrawUriInfoResponse;
}
- confirmWithdrawal#
Confirm a withdrawal transaction.
Confirms a bank-integrated withdrawal that was previously prepared with prepareBankIntegratedWithdrawal, selecting the exchange to withdraw from and, where the withdrawal operation has an editable amount, the amount to withdraw. The exchange’s terms of service must have been accepted and any pending exchange key change must have been confirmed beforehand.
After the confirmation, the user authorizes the actual wire transfer to the exchange in their banking application.
Request:
The request must be a ConfirmWithdrawalRequest object.
Response:
On success, the result is an empty object.
Side effects:
Updates the withdrawal transaction in the wallet database and starts the background task that registers the reserve with the bank and withdraws the coins. May talk to the exchange, the bank integration API and the bank conversion service over the network; when an amount is given, denomination verification results are stored in the database. A sender bank account that is new to the wallet is added to its known bank accounts.
Expected errors:
The caller can handle the following errors inline:
WALLET_KYC_LIMIT_EXCEEDED,WALLET_NO_SUITABLE_EXCHANGE,WALLET_EXCHANGE_TOS_NOT_ACCEPTED,WALLET_TRANSACTION_NOT_FOUND,GENERIC_CURRENCY_MISMATCH,WALLET_CORE_API_BAD_REQUEST,WALLET_EXCHANGE_KEYS_NOT_ACCEPTED.Details:
The
transactionIdmust refer to a withdrawal transaction that is still in the dialog state. Confirming is idempotent: once the withdrawal has been registered with the bank, repeating the confirmation succeeds without further effect.The
amountmay only be omitted for withdrawals from a foreign account (ataler://withdrawURI withexternal-confirmation=1), where the bank fixes the amount when the transfer is confirmed.
interface ConfirmWithdrawalRequest {
transactionId: string;
exchangeBaseUrl: string;
amount?: AmountString | undefined;
forcedDenomSel?: ForcedDenomSel;
restrictAge?: number;
progressToken?: string;
}
interface ForcedDenomSel {
denoms: {
value: AmountString;
count: number;
}[];
}
- acceptBankIntegratedWithdrawaldeprecated#
This operation is deprecated. Use prepareBankIntegratedWithdrawal followed by confirmWithdrawal instead.
Accept a bank-integrated withdrawal in one step, equivalent to preparing the withdrawal and then confirming it with the given exchange and amount. A background task then registers the reserve with the bank and withdraws the coins; once the bank has registered the reserve, the user authorizes the wire transfer in their banking application via the returned
confirmTransferUrl.Request:
The request must be an AcceptBankIntegratedWithdrawalRequest object.
Response:
On success, the result is an AcceptWithdrawalResponse object.
Side effects:
Combines the side effects of prepareBankIntegratedWithdrawal and confirmWithdrawal: creates (or reuses) the withdrawal transaction and starts the task that registers the reserve with the bank and withdraws the coins.
Expected errors:
The caller can handle the following errors inline:
WALLET_EXCHANGE_KEYS_NOT_ACCEPTED.
interface AcceptBankIntegratedWithdrawalRequest {
talerWithdrawUri: string;
exchangeBaseUrl: string;
forcedDenomSel?: ForcedDenomSel;
// Amount to withdraw. If the bank's withdrawal operation uses a
// fixed amount, this field must either be left undefined or its
// value must match the amount from the withdrawal operation.
amount?: AmountString;
restrictAge?: number;
progressToken?: string;
}
interface AcceptWithdrawalResponse {
confirmTransferUrl?: string;
transactionId: TransactionIdStr;
}
- getWithdrawalDetailsForAmount#
Get details for withdrawing a particular amount (manual withdrawal).
Computes the terms of withdrawing the given amount: the raw amount the user has to transfer to the exchange, the effective amount that will be added to the wallet balance after withdrawal fees, the number of coins that would be withdrawn, the exchange’s bank accounts that can receive the transfer (including accounts that require currency conversion), age-restriction options and a preview of KYC requirements.
The client uses the result to let the user review the withdrawal before creating it with acceptManualWithdrawal.
Request:
The request must be a GetWithdrawalDetailsForAmountRequest object.
Response:
On success, the result is a WithdrawalDetailsForAmount object.
Side effects:
May refresh the exchange’s key material over the network, validates withdrawal denominations and stores the verification results in the database, and queries the bank conversion service for accounts that require currency conversion. No transaction is created.
Expected errors:
The caller can handle the following errors inline:
WALLET_EXCHANGE_ENTRY_NOT_FOUND,WALLET_EXCHANGE_TOS_NOT_ACCEPTED,GENERIC_CURRENCY_MISMATCH.Details:
The exchange is selected with
exchangeBaseUrl. When it is omitted,restrictScopenames a currency scope and the wallet’s preferred exchange for that scope is used instead.When
transactionIdrefers to a prepared bank-integrated withdrawal, the sender account of that withdrawal is taken into account when evaluating account-specific withdrawal rules (KYC).An
unconfirmedKeyChangein the result means the exchange changed its key set and the user has not confirmed the change yet; accepting the withdrawal will be refused until the change is confirmed with confirmExchangeKeyChange, so this is the point at which to warn the user.
interface GetWithdrawalDetailsForAmountRequest {
exchangeBaseUrl?: string;
// Prepared bank-integrated withdrawal whose sender account should
// be checked.
transactionId?: TransactionIdStr;
// Specify currency scope for the withdrawal.
// May only be used when exchangeBaseUrl is not specified.
restrictScope?: ScopeInfo;
amount: AmountString;
restrictAge?: number;
progressToken?: string;
}
interface WithdrawalDetailsForAmount extends WithdrawalKycPreview {
// Exchange base URL for the withdrawal.
exchangeBaseUrl: string;
// Amount that the user will transfer to the exchange.
amountRaw: AmountString;
// Amount that will be added to the user's wallet balance.
amountEffective: AmountString;
// Number of coins that would be used for withdrawal.
// UIs should warn if this number is too high (roughly at >100).
numCoins: number;
// Ways to pay the exchange, including accounts that require
// currency conversion.
withdrawalAccountsList: WithdrawalExchangeAccountDetails[];
// If the exchange supports age-restricted coins it will return
// the array of ages.
ageRestrictionOptions?: number[];
// Scope info of the currency withdrawn.
scopeInfo: ScopeInfo;
// Set when the exchange changed its key set and the user has not
// confirmed the change. Accepting the withdrawal will be refused
// until they do, so this is the point at which to warn them.
unconfirmedKeyChange?: ExchangeKeyChangeInfo;
// KYC soft limit.
// Withdrawals over that amount will require KYC.
kycSoftLimit?: AmountString;
// KYC hard limit.
// Withdrawals over that amount will be denied.
kycHardLimit?: AmountString;
// Ways to pay the exchange.
// Deprecated in favor of withdrawalAccountsList.
paytoUris: string[];
}
interface WithdrawalKycPreview {
// Whether the proposed withdrawal needs a KYC warning based on
// this wallet's balance, known KYC allowance, advertised
// zero-limit rules and known withdrawal volume. This is a
// preview, not a guarantee that the exchange will not require
// KYC. Optional for compatibility with older wallet-core
// versions, which omit it.
kycRequired?: boolean;
// Balance usage from the same evaluation as kycRequired.
balanceKyc?: BalanceKycUsage;
// Account-specific withdrawal-rule preview using this wallet's
// history. "ok" only covers exposed rules and available local
// history; "unknown" means account limits could not be evaluated
// and must not be shown as clearance. Older wallet-core versions
// omit this field.
withdrawalKycStatus?: WithdrawalKycStatus;
}
// This wallet's balance at the issuing exchange at preview time,
// using the same accounting as balance-KYC enforcement (including
// pending refresh outputs). Does not reserve capacity for
// concurrent withdrawals or report account-wide
// transaction-volume/hard-limit usage.
interface BalanceKycUsage {
currentBalance: AmountString;
// Current balance plus the selected coins' value after withdrawal
// fees.
projectedBalance: AmountString;
// Applicable balance threshold; omitted when no finite limit is
// known.
threshold?: AmountString;
// Additional balance permitted, clamped to zero; omitted with
// threshold.
remaining?: AmountString;
}
type WithdrawalKycStatus =
| "unknown"
| "ok"
| "kyc-required"
| "hard-limit";
interface WithdrawalExchangeAccountDetails {
// Payto URI of the exchange. Depending on whether the (manual!)
// withdrawal is accepted or just being checked, this already
// includes the subject with the reserve public key.
paytoUri: string;
// Whether the account can be used by the user to send funds for a
// withdrawal. "ok": account should be shown to the user;
// "error": account should not be shown to the user, UIs might
// render the error (in conversionError), especially in dev mode.
status: "ok" | "error";
// Transfer amount. Might be in a different currency than the
// requested amount for withdrawal. Absent if this is a
// conversion account and the conversion failed.
transferAmount?: AmountString;
// Currency specification for the external currency.
// Only included if this account requires a currency conversion.
currencySpecification?: CurrencySpecification;
// Further restrictions for sending money to the exchange.
creditRestrictions?: AccountRestriction[];
// Label given to the account or the account's bank by the
// exchange.
bankLabel?: string;
// Display priority assigned to this bank account by the exchange.
priority?: number;
// Error that happened when attempting to request the conversion
// rate.
conversionError?: TalerErrorDetail;
// Timestamp that indicates when the transfer options expire.
// If missing, options do not expire.
transferExpiry?: TalerProtocolTimestamp;
// Options for transferring funds to the exchange for the
// withdrawal.
transferOptions: TransferOption[];
}
type TransferOption =
| TransferOptionPayto
| TransferOptionUri
| TransferOptionSwissQrBill;
interface TransferOptionPayto {
type: "payto";
paytoUri: string;
qrCodes: QrCodeSpec[];
}
interface TransferOptionUri {
type: "uri";
uri: string;
}
interface TransferOptionSwissQrBill {
type: "ch-qr-bill";
paytoUri: string;
qrReferenceNumber: string;
qrCodes: QrCodeSpec[];
}
- acceptManualWithdrawal#
Create a manual withdrawal.
Creates a withdrawal transaction for the given amount at the given exchange, with a freshly generated reserve key pair. The user must then wire the amount to one of the exchange’s bank accounts returned in the result; the
paytoUriof each account already includes the reserve public key as the transfer subject. Once the transfer arrives at the exchange, wallet-core withdraws the coins.Request:
The request must be an AcceptManualWithdrawalRequest object.
Response:
On success, the result is an AcceptManualWithdrawalResult object.
Side effects:
Creates the withdrawal transaction (with a fresh reserve key pair) in the wallet database and starts the background task that watches the reserve and withdraws the coins once the transfer arrives. May refresh exchange information and query the bank conversion service over the network.
Expected errors:
The caller can handle the following errors inline:
WALLET_KYC_LIMIT_EXCEEDED,WALLET_EXCHANGE_TOS_NOT_ACCEPTED,GENERIC_CURRENCY_MISMATCH,WALLET_EXCHANGE_KEYS_NOT_ACCEPTED.
interface AcceptManualWithdrawalRequest {
exchangeBaseUrl: string;
amount: AmountString;
restrictAge?: number;
// Instead of generating a fresh, random reserve key pair, use
// the provided reserve private key. Use with caution. Usage of
// this field may be restricted to developer mode.
forceReservePriv?: EddsaPrivateKeyString;
progressToken?: string;
}
interface AcceptManualWithdrawalResult {
// Transaction ID of the newly created withdrawal transaction.
transactionId: TransactionIdStr;
// Public key of the newly created reserve.
reservePub: string;
// Bank accounts of the exchange that can be used to fund the
// withdrawal.
withdrawalAccountsList: WithdrawalExchangeAccountDetails[];
}
- getWithdrawalDetailsForUrideprecated#
This operation is deprecated. Use prepareBankIntegratedWithdrawal instead.
Get details for withdrawing via a
taler://withdrawURI, without creating a withdrawal transaction.Request:
The request must be a GetWithdrawalDetailsForUriRequest object.
Response:
On success, the result is a WithdrawUriInfoResponse object (see prepareBankIntegratedWithdrawal).
Side effects:
Queries the bank’s bank integration API over the network; the exchange suggested by the bank may be fetched and ephemerally added to the wallet’s known exchanges. No transaction is created.
Expected errors:
The caller can handle the following errors inline:
WALLET_TALER_URI_MALFORMED.
interface WithdrawUriInfoResponse {
operationId: string;
status: WithdrawalOperationStatusFlag;
// URL for confirming the transfer at the bank.
confirmTransferUrl?: string;
currency: string;
// Amount that will be withdrawn (raw amount, without fee
// considerations). Only given once the amount is fixed.
amount: AmountString | undefined;
// Set to true if the user is allowed to edit the amount.
// Note that even with a non-editable amount, the amount might be
// undefined at the beginning of the withdrawal process.
editableAmount: boolean;
// Maximum amount that the wallet can choose to withdraw.
maxAmount: AmountString | undefined;
wireFee: AmountString | undefined;
// Exchange suggested by the bank, if any.
defaultExchangeBaseUrl?: string;
editableExchange: boolean;
// Exchanges that can be used for the withdrawal, filtered to the
// currency of the withdrawal operation. If the exchange is not
// editable, contains only the bank-suggested exchange.
possibleExchanges: ExchangeListItem[];
}
// Status of a bank-integrated withdrawal operation:
// - "pending": pending parameter selection (exchange and reserve
// public key)
// - "selected": parameters selected, pending confirmation
// - "aborted": the operation has been aborted
// - "confirmed": the transfer has been confirmed and registered by
// the bank
type WithdrawalOperationStatusFlag =
| "pending"
| "selected"
| "aborted"
| "confirmed";
interface GetWithdrawalDetailsForUriRequest {
talerWithdrawUri: string;
// Deprecated, not used.
restrictAge?: number;
progressToken?: string;
}
20.5.4.7. Merchant payments#
Payment operations handle taler://pay/ and taler://pay-template/
URIs as well as payments to Paivana-protected resources, and follow-up
actions such as refund queries and payment hand-off between wallets.
- getChoicesForPayment#
Get the list of contract choices for a payment transaction in the dialog (confirmation) state, together with information on whether each choice can be paid with the funds available in the wallet, and whether a specific choice should be paid automatically without user confirmation, based on the user’s configuration or the type of payment requested.
For a contract v1 order, the
choicesarray of the result mirrors the choices of the contract. For a contract v0 order, which has no choices, it contains a single choice with no inputs/outputs.Request:
The
argsmust be a GetChoicesForPaymentRequest object.Response:
On success, the result is a GetChoicesForPaymentResult object.
Side effects:
None; this operation is a pure read. The payability of each choice is evaluated against the coin, exchange and token information already stored in the wallet database, without any network access.
Expected errors:
The caller can handle the following errors inline:
WALLET_REQUEST_TRANSACTION_STATE_UNSUPPORTED,WALLET_TRANSACTION_NOT_FOUND,WALLET_CORE_API_BAD_REQUEST.The
WALLET_REQUEST_TRANSACTION_STATE_UNSUPPORTEDerror is returned while the contract terms of the payment have not been downloaded yet; the caller should wait for the corresponding transaction state transition and try again.
interface GetChoicesForPaymentRequest {
// Transaction identifier of the payment.
transactionId: string;
// Force a particular coin selection when evaluating
// whether the choices are payable.
forcedCoinSel?: ForcedCoinSel;
}
interface ForcedCoinSel {
coins: {
value: AmountString;
contribution: AmountString;
}[];
}
type GetChoicesForPaymentResult = {
// Details for all choices in the contract.
//
// The index in this array corresponds to the choice
// index in the original contract v1. For contract v0
// orders, it will only contain a single choice with no
// inputs/outputs.
choices: ChoiceSelectionDetail[];
// Index of the choice in the choices array to present
// to the user as default.
//
// Won't be set if no default selection is configured
// or no choice is payable; otherwise it will always
// be 0 for v0 orders.
defaultChoiceIndex?: number;
// Whether the choice referenced by automaticExecutableIndex
// should be confirmed automatically without user interaction.
//
// If true, the wallet should call confirmPay immediately
// afterwards; if false, the user should first be prompted
// to select and confirm a choice. Undefined when no
// choices are payable.
automaticExecution?: boolean;
// Index of the choice that would be set to automatically
// execute if the choice was payable. When automaticExecution
// is set to true, the payment should be confirmed with this
// choice index without user interaction.
automaticExecutableIndex?: number;
// Data extracted from the contract terms that
// is relevant for payment processing in the wallet.
contractTerms: MerchantContractTerms;
};
type ChoiceSelectionDetail =
| ChoiceSelectionDetailPaymentPossible
| ChoiceSelectionDetailInsufficientBalance;
interface ChoiceSelectionDetailPaymentPossible {
status: ChoiceSelectionDetailType.PaymentPossible;
// Amount requested by the contract for this choice.
amountRaw: AmountString;
// Total cost of this choice for the wallet, including fees.
amountEffective: AmountString;
// Scope of the coins that would be spent, if known.
scopeInfo: ScopeInfo | undefined;
tokenDetails?: PaymentTokenAvailabilityDetails;
}
interface ChoiceSelectionDetailInsufficientBalance {
status: ChoiceSelectionDetailType.InsufficientBalance;
// Amount requested by the contract for this choice.
amountRaw: AmountString;
balanceDetails?: PaymentInsufficientBalanceDetails;
tokenDetails?: PaymentTokenAvailabilityDetails;
}
type ChoiceSelectionDetailType =
| "payment-possible"
| "insufficient-balance";
interface PaymentTokenAvailabilityDetails {
// Number of tokens requested by the merchant.
tokensRequested: number;
// Number of tokens available to use.
tokensAvailable: number;
// Legacy compatibility field. Always zero: tokens from another
// merchant are counted as untrusted and cannot be used.
tokensUnexpected: number;
// Number of tokens not issued by the receiving merchant.
//
// Cannot be used to pay, so an error should be displayed.
tokensUntrusted: number;
perTokenFamily: {
[slug: string]: {
causeHint?: TokenAvailabilityHint;
requested: number;
available: number;
unexpected: number;
untrusted: number;
};
};
}
type TokenAvailabilityHint =
| "wallet-tokens-available-insufficient"
| "merchant-unexpected"
| "merchant-untrusted";
- preparePayForUriV2#
Prepare to make a payment based on a
taler://pay/URI.Creates a payment transaction for the order identified by the URI, or reuses the existing transaction if the wallet already knows the order. The contract terms are then downloaded and processed by the transaction. Use getChoicesForPayment to inspect the payable choices and confirmPay to confirm the payment.
Request:
The
argsmust be a PreparePayRequest object.Response:
On success, the result is a PreparePayV2Result object.
Side effects:
The operation itself is deliberately local-only: it creates (or reuses) the payment transaction record in the wallet database and wakes the transaction’s background task. Claiming the order and downloading the contract terms from the merchant happen asynchronously as part of the transaction’s processing; the transaction moves to dialog state once the contract terms have been downloaded.
Expected errors:
The caller can handle the following errors inline:
WALLET_INVALID_TALER_PAY_URI.Errors from claiming the order and downloading the contract terms (such as
WALLET_MERCHANT_ORDER_NOT_FOUND,WALLET_ORDER_ALREADY_CLAIMED,WALLET_ORDER_ALREADY_PAID,WALLET_CONTRACT_TERMS_MALFORMEDorWALLET_CONTRACT_TERMS_UNSUPPORTED) do not fail this operation; they are reported as the last error of the payment transaction.
interface PreparePayRequest {
// The taler://pay/ URI to pay.
talerPayUri: string;
}
interface PreparePayV2Result {
// Transaction identifier of the payment transaction.
transactionId: TransactionIdStr;
}
- preparePayForTemplateV2#
Prepare to make a payment based on a
taler://pay-template/URI.Instantiates the referenced order template at the merchant, honoring
templateParamsfor template fields that are editable by the customer, and creates (or reuses) a payment transaction for the resulting order. As with preparePayForUriV2, the payment is then inspected with getChoicesForPayment and confirmed with confirmPay.Request:
The
argsmust be a PreparePayTemplateRequest object.Response:
On success, the result is a PreparePayV2Result object.
Side effects:
Fetches the payment template from the merchant over the network and creates a payment transaction in dialog state.
Expected errors:
The caller can handle the following errors inline:
WALLET_TALER_URI_MALFORMED,WALLET_CONTRACT_TERMS_UNSUPPORTED.
interface PreparePayTemplateRequest {
// The taler://pay-template/ URI to pay.
talerPayTemplateUri: string;
// Values for editable template fields.
templateParams?: TemplateParams;
// Enables progress correlation and cancellation through
// cancelProgressToken.
progressToken?: string;
}
type TemplateParams = {
amount?: AmountString;
summary?: string;
};
- preparePayForPaivana#
Prepare a payment for an HTTP(S) resource protected by a Paivana paywall.
The wallet requests the given
url, expects an HTTP 402 response that advertises a payment template in thePaivanaheader, instantiates that template into an order and creates (or reuses) a payment transaction for it. The returnedpaivanaredemption metadata must be kept by the client; once the payment has succeeded, it is passed to getPaivanaCookie to obtain the access cookie for the resource.Request:
The
argsmust be a PreparePayForPaivanaRequest object.Response:
On success, the result is a PreparePayForPaivanaResult object.
Side effects:
Fetches the contract terms for the Paivana-protected resource over the network and creates a payment transaction in dialog state.
Expected errors:
The caller can handle the following errors inline:
WALLET_CORE_API_BAD_REQUEST,WALLET_RECEIVED_MALFORMED_RESPONSE,WALLET_NETWORK_ERROR,WALLET_HTTP_REQUEST_THROTTLED,WALLET_HTTP_REQUEST_GENERIC_TIMEOUT,WALLET_UNEXPECTED_REQUEST_ERROR,WALLET_CONTRACT_TERMS_UNSUPPORTED.
interface PreparePayForPaivanaRequest {
// URL of the Paivana-protected resource to pay for.
url: string;
// Enables progress correlation and cancellation through
// cancelProgressToken.
progressToken?: string;
}
interface PreparePayForPaivanaResult {
// Transaction identifier of the payment transaction.
transactionId: TransactionIdStr;
paivana: PaivanaRedemption;
}
// Information needed to redeem a paid Paivana order for an
// access cookie.
interface PaivanaRedemption {
// Canonical HTTP(S) URL of the protected resource.
url: string;
// Crockford-base32 encoded 16-byte client nonce.
nonce: string;
// End of the access period used to derive the Paivana
// session ID.
expiration: TalerProtocolTimestamp;
}
- getPaivanaCookie#
Redeem a successfully paid Paivana transaction for an access cookie.
The payment transaction referenced by
transactionIdmust have completed successfully, and thepaivanaredemption metadata must match the one returned by preparePayForPaivana for that transaction. The wallet redeems the paid order at the Paivana endpoint of the protected resource and returns the access cookie; the client can then request the resource with this cookie. Error codes with thePAIVANA_prefix are reported by the Paivana server and forwarded by the wallet.Request:
The
argsmust be a GetPaivanaCookieRequest object.Response:
On success, the result is a GetPaivanaCookieResult object.
Side effects:
Redeems the paid Paivana transaction for an access cookie via an HTTP POST to the resource server.
Expected errors:
The caller can handle the following errors inline:
WALLET_CORE_API_BAD_REQUEST,WALLET_TRANSACTION_NOT_FOUND,WALLET_REQUEST_TRANSACTION_STATE_UNSUPPORTED,WALLET_RECEIVED_MALFORMED_RESPONSE,WALLET_NETWORK_ERROR,WALLET_HTTP_REQUEST_THROTTLED,WALLET_HTTP_REQUEST_GENERIC_TIMEOUT,PAIVANA_PAYMENT_MISSING,PAIVANA_BACKEND_REFUSED,PAIVANA_ORDER_UNKNOWN,PAIVANA_BACKEND_ERROR,PAIVANA_GET_ORDER_FAILED,PAIVANA_WRONG_ORDER,PAIVANA_TOO_LATE,PAIVANA_INVALID_TARGET.
interface GetPaivanaCookieRequest {
// Transaction identifier of the paid Paivana payment.
transactionId: TransactionIdStr;
paivana: PaivanaRedemption;
}
interface GetPaivanaCookieResult {
// Plain Cookie request-header value, without Set-Cookie
// attributes.
cookie: string;
}
- unclaimPayment#
Release this wallet’s claim on an unpaid order, so that the payment can be handed off to another wallet.
The merchant is asked to release the order, and the operation returns a public
taler://pay/URI for the order that contains no private nonce. Another wallet can use this URI with preparePayForUriV2 to claim and pay the order instead. The payment can only be released before it is paid; use reclaimPayment to claim the order again for this wallet.Request:
The
argsmust be an UnclaimPaymentRequest object.Response:
On success, the result is an UnclaimPaymentResult object.
Side effects:
Unclaims the payment at the merchant and generates a taler://pay URI that allows another wallet to complete it; changes the transaction state.
Expected errors:
The caller can handle the following errors inline:
WALLET_TRANSACTION_NOT_FOUND,WALLET_REQUEST_TRANSACTION_STATE_UNSUPPORTED,WALLET_CORE_REQUEST_CANCELLED,WALLET_UNEXPECTED_REQUEST_ERROR.
interface UnclaimPaymentRequest {
// Transaction identifier of the payment to release.
transactionId: TransactionIdStr;
// Enables progress correlation and cancellation through
// cancelProgressToken.
progressToken?: string;
}
interface UnclaimPaymentResult {
// Public taler://pay/ URI that another wallet can claim.
talerPayUri: TalerUriString;
}
- reclaimPayment#
Claim an order again for this wallet after it was released for handoff with unclaimPayment. Claiming again with the same nonce is idempotent.
Request:
The
argsmust be a ReclaimPaymentRequest object.Response:
On success, the result is an empty object.
Side effects:
Reclaims a payment previously handed off to another wallet; changes the transaction state.
Expected errors:
The caller can handle the following errors inline:
WALLET_TRANSACTION_NOT_FOUND,WALLET_REQUEST_TRANSACTION_STATE_UNSUPPORTED.
interface ReclaimPaymentRequest {
// Transaction identifier of the payment to claim again.
transactionId: TransactionIdStr;
}
- checkPayForTemplate#
Check a
taler://pay-template/URI without creating a payment transaction.Fetches the template details from the merchant, applies the overrides encoded in the URI (such as amount or summary), and returns the template details together with the currencies supported by the merchant. This allows the client to present the editable template fields to the user before calling preparePayForTemplateV2.
Request:
The
argsmust be a CheckPayTemplateRequest object.Response:
On success, the result is a CheckPayTemplateReponse object.
Side effects:
Fetches the payment template and the merchant’s configuration over the network; does not change wallet state.
Expected errors:
The caller can handle the following errors inline:
WALLET_TALER_URI_MALFORMED,WALLET_CONTRACT_TERMS_UNSUPPORTED.Details:
The
templateDetailsfield is the template information served by the merchant backend (a WalletTemplateDetailsResponse of the merchant API), with the URI overrides already applied.
interface CheckPayTemplateRequest {
// The taler://pay-template/ URI to check.
talerPayTemplateUri: string;
// Enables progress correlation and cancellation through
// cancelProgressToken.
progressToken?: string;
}
type CheckPayTemplateReponse = {
// Template details served by the merchant backend.
templateDetails: WalletTemplateDetailsResponse;
// Currencies supported by the merchant, sorted.
supportedCurrencies: string[];
};
- startRefundQueryForUri#
Check for a refund based on a
taler://refundURI.Locates the payment for the order identified by the URI and starts a refund query on it; the refund processing then continues as part of the payment transaction. The
WALLET_PURCHASE_NOT_FOUNDerror is returned when the wallet has no purchase for the order, for example because it was paid with a different wallet.Request:
The
argsmust be a PrepareRefundRequest object.Response:
On success, the result is a StartRefundQueryForUriResponse object.
Side effects:
Creates or updates a refund query and contacts the merchant over the network.
Expected errors:
The caller can handle the following errors inline:
WALLET_TALER_URI_MALFORMED,WALLET_PURCHASE_NOT_FOUND.
interface PrepareRefundRequest {
// The taler://refund URI to check for refunds.
talerRefundUri: string;
}
interface StartRefundQueryForUriResponse {
// Transaction id of the *payment* where the refund query
// was started.
transactionId: TransactionIdStr;
}
- startRefundQuery#
Start a refund query for an existing payment transaction, referenced by its transaction identifier. Only payments that completed successfully are queried; for payments in any other state, the request has no effect.
Request:
The
argsmust be a StartRefundQueryRequest object.Response:
On success, the result is an empty object.
Side effects:
Starts a refund query for an existing payment transaction, contacting the merchant over the network.
interface StartRefundQueryRequest {
// Transaction identifier of the payment to query refunds for.
transactionId: TransactionIdStr;
}
- 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";
20.5.4.8. Deposits#
Deposit operations send coins from the wallet to a bank account, usually the wallet user’s own account.
- checkDeposit#
Check whether a deposit of the given amount to the given target account is possible with the funds in the wallet, and calculate the associated fees, without creating a deposit transaction.
Request:
The request body must be a CheckDepositRequest object.
Response:
On success, the result is a CheckDepositResponse object.
Side effects:
May refresh the key material of the exchanges holding the selected coins over the network, including exchange record updates and notifications.
Expected errors:
The caller can handle the following errors inline:
GENERIC_PAYTO_URI_MALFORMED,WALLET_NO_SUITABLE_EXCHANGE,WALLET_DEPOSIT_GROUP_INSUFFICIENT_BALANCE.Details:
totalDepositCostis the total cost to the wallet: the contributions of the selected coins plus the cost of refreshing any change.effectiveDepositAmountis the amount expected to be wired to the destination account (not considering aggregation).
interface CheckDepositRequest {
// Payto URI to identify the (bank) account that the exchange will
// wire the money to.
depositPaytoUri: string;
// Instructed amount used for deposit coin selection. The response
// reports the resulting wallet cost and destination amount, which
// can differ because of fees and refresh change.
amount: AmountString;
// Restrict the deposit to a certain scope.
restrictScope?: ScopeInfo;
progressToken?: string;
}
interface CheckDepositResponse {
totalDepositCost: AmountString;
effectiveDepositAmount: AmountString;
fees: DepositGroupFees;
kycSoftLimit?: AmountString;
kycHardLimit?: AmountString;
// Base URL of exchanges that would likely require soft KYC.
kycExchanges?: string[];
}
interface DepositGroupFees {
// Deposit fees of the selected coins.
coin: AmountString;
// Wire fees of the involved exchanges.
wire: AmountString;
// Cost of refreshing change from the selected coins.
refresh: AmountString;
}
- createDepositGroup#
Create a new deposit group. Deposit groups are used to deposit multiple coins to a bank account, usually the wallet user’s own bank account.
The deposit is executed asynchronously as a transaction; the response returns the transaction identifier and its initial state. The fees of the deposit can be reviewed beforehand with checkDeposit.
Request:
The request body must be a CreateDepositGroupRequest object.
Response:
On success, the result is a CreateDepositGroupResponse object.
Side effects:
Creates a deposit group transaction and deposits the coins at the exchange over the network.
Expected errors:
The caller can handle the following errors inline:
GENERIC_PAYTO_URI_MALFORMED,WALLET_NO_SUITABLE_EXCHANGE,WALLET_DEPOSIT_GROUP_INSUFFICIENT_BALANCE,WALLET_KYC_LIMIT_EXCEEDED.
interface CreateDepositGroupRequest {
depositPaytoUri: string;
// Instructed amount used for deposit coin selection.
amount: AmountString;
// Restrict the deposit to a certain scope.
restrictScope?: ScopeInfo;
// Use a fixed merchant private key.
testingFixedPriv?: string;
// Optional wire deadline for the deposits.
wireDeadline?: TalerProtocolTimestamp;
// Pre-allocated transaction ID. Allows clients to easily handle
// notifications that occur while the operation has been created
// but before the creation request has returned.
transactionId?: TransactionIdStr;
progressToken?: string;
}
// Response to a createDepositGroup request.
interface CreateDepositGroupResponse {
// Transaction ID of the newly created deposit transaction.
transactionId: TransactionIdStr;
// Current state of the new deposit transaction. Returned as a
// performance optimization, so that the UI doesn't have to do a
// separate getTransactionById.
txState: TransactionState;
// Deprecated, use transactionId instead.
depositGroupId: string;
}
- convertDepositAmountread-onlydeprecated#
This operation is deprecated. Use checkDeposit for a concrete instructed amount, or getMaxDepositAmount to query deposit limits.
Compute the effective and raw amounts for a deposit of the given instructed amount, based on the coins currently available in the wallet. The
typefield (TransactionAmountMode) selects whetheramountis interpreted as an effective or as a raw amount.Request:
The request body must be a ConvertAmountRequest object.
Response:
On success, the result is an AmountResponse object.
// Deprecated: use CheckDepositRequest for a concrete instructed
// amount, or GetMaxDepositAmountRequest to query deposit limits.
interface ConvertAmountRequest {
amount: AmountString;
type: TransactionAmountMode;
depositPaytoUri: PaytoString;
}
interface AmountResponse {
effectiveAmount: AmountString;
rawAmount: AmountString;
}
- getMaxDepositAmountread-only#
Query the maximum amount that can currently be deposited in the given currency.
Request:
The request body must be a GetMaxDepositAmountRequest object. When
depositPaytoUriis omitted, wire-method eligibility, account restrictions and wire fees cannot be reflected in the response.Response:
On success, the result is a GetMaxDepositAmountResponse object.
Details:
The result distinguishes the maximum that can be deposited immediately (
material) from the maximum that also includes the expected outputs of pending refresh operations (available).exchangeDiagnosticsgives, for every ready same-currency exchange, the per-exchange maximums and the reasons why the exchange cannot serve the deposit.
interface GetMaxDepositAmountRequest {
// Currency to deposit.
currency: string;
// Target bank account to deposit into. When omitted, wire-method
// eligibility, account restrictions and wire fees cannot be
// reflected in the response.
depositPaytoUri?: string;
// Restrict the deposit to a certain scope.
restrictScope?: ScopeInfo;
}
interface GetMaxDepositAmountResponse {
// Maximum that can be deposited immediately.
material: DepositMaximum;
// Maximum including expected outputs of pending refresh
// operations.
available: DepositMaximum;
// Eligibility and maximum amounts for every ready same-currency
// exchange.
exchangeDiagnostics: Record<string, DepositExchangeDiagnostics>;
}
// Maximum amounts and fees for one coherent deposit coin selection.
interface DepositMaximum {
// Gross target amount passed to checkDeposit or
// createDepositGroup.
instructedAmount: AmountString;
// Total balance effect on the wallet: instructed amount plus fees
// paid by the customer and the cost of refreshing any change.
effectiveAmount: AmountString;
// Amount expected to reach the destination account: instructed
// amount minus fees covered by the counterparty.
rawAmount: AmountString;
// Total fees incurred by this deposit selection.
fees: DepositGroupFees;
}
interface DepositExchangeDiagnostics {
// Maximum that can be deposited immediately.
material: DepositMaximum;
// Maximum including expected outputs of pending refresh
// operations.
available: DepositMaximum;
// Eligibility failures, in deterministic evaluation order.
reasons: DepositEligibilityReason[];
}
// Reason why a ready, same-currency exchange cannot serve a deposit.
type DepositEligibilityReason =
| { type: "direct-deposit-disabled" }
| { type: "scope-restricted"; scopeInfo: ScopeInfo }
| { type: "wire-method-unsupported"; wireMethod: string }
| { type: "wire-fee-unavailable"; wireMethod: string }
| {
type: "deposit-account-restricted";
wireMethod: string;
accountRestrictions: Record<string, AccountRestriction[]>;
};
type DepositEligibilityReasonType =
"direct-deposit-disabled"
| "scope-restricted"
| "wire-method-unsupported"
| "wire-fee-unavailable"
| "deposit-account-restricted";
type AccountRestriction =
| RegexAccountRestriction
| DenyAllAccountRestriction;
// Accounts interacting with this type of account restriction must
// have a payto://-URI matching the given regex.
interface RegexAccountRestriction {
type: "regex";
// Regular expression that the payto://-URI of the partner account
// must follow (posix-egrep, without support for character
// classes, GNU extensions, back-references or intervals).
payto_regex: string;
// Hint for a human to understand the restriction.
human_hint: string;
// Map from IETF BCP 47 language tags to localized human hints.
human_hint_i18n?: InternationalizedString;
}
interface DenyAllAccountRestriction {
type: "deny";
}
- getDepositWireTypesread-only#
Get the wire types that can be used as the target of a deposit, together with per-type details. The result is derived from the wire accounts of the exchanges known to the wallet; accounts with a deny-type debit restriction are excluded. When
currencyis given, only exchanges for that currency are considered.Request:
The request body must be a GetDepositWireTypesRequest object.
Response:
On success, the result is a GetDepositWireTypesResponse object.
interface GetDepositWireTypesRequest {
currency?: string;
// Optional scope info to further restrict the result.
// Currency must match the currency field.
scopeInfo?: ScopeInfo;
}
interface GetDepositWireTypesResponse {
// Details for each wire type.
wireTypeDetails: WireTypeDetails[];
}
interface WireTypeDetails {
paymentTargetType: string;
// Only applicable for payment target type IBAN. Specifies
// whether the user wants to preferably enter their bank account
// details as an IBAN or as a BBAN. Mandatory for
// paymentTargetType="iban".
preferredEntryType?: "iban" | "bban";
// Allowed hostnames for the deposit payto URI. Only applicable to
// x-taler-bank.
talerBankHostnames?: string[];
}
- getDepositWireTypesForCurrencyread-onlydeprecated#
This operation is deprecated. Use getDepositWireTypes instead.
Get wire types that can be used for a deposit operation with the provided currency.
Request:
The request body must be a GetDepositWireTypesForCurrencyRequest object.
Response:
On success, the result is a GetDepositWireTypesForCurrencyResponse object.
interface GetDepositWireTypesForCurrencyRequest {
currency: string;
// Optional scope info to further restrict the result.
// Currency must match the currency field.
scopeInfo?: ScopeInfo;
}
// Response with wire types that are supported for a deposit.
interface GetDepositWireTypesForCurrencyResponse {
// Deprecated, use wireTypeDetails instead.
wireTypes: string[];
// Details for each wire type.
wireTypeDetails: WireTypeDetails[];
}
20.5.4.9. Peer-to-peer payments#
Peer-to-peer payments move funds directly between two wallets. In a push payment, the sender initiates the transfer; in a pull payment, the receiver requests to be paid by the sender.
- preparePeerPushCredit#
Check an incoming peer push payment. The payment is identified either by a
taler://pay-push/URI received from the sender or by thetransactionIdof an existing peer-push-credit transaction.Request:
The request body must be a PreparePeerPushCreditRequest object. Either
talerUriortransactionIdmust be specified.Response:
On success, the result is a PreparePeerPushCreditResponse object, carrying the contract terms and the amounts the wallet would receive, so that the user can review the payment before accepting it with confirmPeerPushCredit.
Side effects:
Fetches the contract and purse status from the exchange over the network and creates an incoming peer push payment transaction in dialog state.
Expected errors:
The caller can handle the following errors inline:
WALLET_PEER_CONTRACT_NOT_FOUND,WALLET_PEER_PUSH_CREDIT_PURSE_GONE,WALLET_TALER_URI_MALFORMED,WALLET_TRANSACTION_NOT_FOUND.Details:
Calling the operation again with the same
talerUrior with the resultingtransactionIdreturns the state of the existing transaction instead of fetching the contract again.
// Either talerUri or transactionId must be specified.
interface PreparePeerPushCreditRequest {
talerUri?: string;
transactionId?: string;
progressToken?: string;
}
interface PreparePeerPushCreditResponse {
contractTerms: PeerContractTerms;
amountRaw: AmountString;
amountEffective: AmountString;
transactionId: TransactionIdStr;
// State of the existing or newly created transaction.
txState: TransactionState;
exchangeBaseUrl: string;
scopeInfo: ScopeInfo;
// Deprecated.
amount: AmountString;
}
// Contract terms between two wallets (as opposed to a merchant and
// wallet).
interface PeerContractTerms {
amount: AmountString;
summary: string;
icon_id?: string;
purse_expiration: TalerProtocolTimestamp;
}
- checkPeerPushDebitdeprecated#
This operation is deprecated. Use checkPeerPushDebitV2 instead.
Check if initiating a peer push payment is possible based on the funds in the wallet. Unlike the V2 operation, an insufficient balance is reported via the
WALLET_PEER_PUSH_PAYMENT_INSUFFICIENT_BALANCEerror instead of a typed result.Request:
The request body must be a CheckPeerPushDebitRequest object.
Response:
On success, the result is a CheckPeerPushDebitOkResponse object.
Side effects:
May refresh the selected exchange’s key material over the network.
Expected errors:
The caller can handle the following errors inline:
WALLET_PEER_PUSH_PAYMENT_INSUFFICIENT_BALANCE(also reported when no exchange can serve the payment),WALLET_CORE_API_BAD_REQUEST.
interface CheckPeerPushDebitRequest {
// Preferred exchange to use for the p2p payment.
exchangeBaseUrl?: string;
// Instructed amount.
amount: AmountString;
// Restrict the scope of funds that can be spent via the given
// scope info.
restrictScope?: ScopeInfo;
progressToken?: string;
}
interface CheckPeerPushDebitOkResponse {
type: "ok";
amountRaw: AmountString;
amountEffective: AmountString;
// Exchange base URL.
exchangeBaseUrl: string;
// Maximum expiration date, based on how close the coins used for
// the payment are to expiry. The value is based on when the
// wallet would typically refresh the coins on its own, leaving
// enough time to get a refund for the push payment and refresh
// the coin.
maxExpirationDate: TalerProtocolTimestamp;
// Default expiration: the default given by the exchange
// (or 1 week if the exchange does not specify it), capped so
// that the purse does not outlive the coins' maxExpirationDate.
defaultExpiration: TalerProtocolDuration;
// Opaque description of the values reviewed by the caller.
// Passing this back to initiatePeerPushDebit makes wallet-core
// reject the operation when coin selection, fees or the selected
// exchange changed in the meantime. Optional for compatibility
// with older wallet-core implementations.
peerPushDebitQuote?: string;
}
- checkPeerPushDebitV2#
Check if initiating a peer push payment is possible based on the funds in the wallet.
Request:
The request body must be a CheckPeerPushDebitRequest object.
Response:
On success, the result is a CheckPeerPushDebitResponse object, a discriminated union on the
typefield:"ok"(CheckPeerPushDebitOkResponse) carries the reviewed amounts and a quote for initiatePeerPushDebit;"insufficient-balance"(CheckPeerPushDebitInsufficientBalanceResponse) explains why the wallet cannot cover the payment.Side effects:
May refresh the selected exchange’s key material over the network.
Expected errors:
The caller can handle the following errors inline:
WALLET_CORE_API_BAD_REQUEST.An insufficient balance (including the case where no exchange can serve the payment) is not reported as an error but via the typed
"insufficient-balance"result.
type CheckPeerPushDebitResponse =
| CheckPeerPushDebitOkResponse
| CheckPeerPushDebitInsufficientBalanceResponse;
interface CheckPeerPushDebitInsufficientBalanceResponse {
type: "insufficient-balance";
insufficientBalanceDetails: PaymentInsufficientBalanceDetails;
}
- initiatePeerPushDebit#
Initiate an outgoing peer push payment.
Request:
The request body must be an InitiatePeerPushDebitRequest object.
Response:
On success, the result is an InitiatePeerPushDebitResponse object.
Side effects:
Creates an outgoing peer push payment transaction, locking the coins.
Expected errors:
The caller can handle the following errors inline:
WALLET_PEER_PUSH_PAYMENT_INSUFFICIENT_BALANCE,WALLET_PEER_PUSH_PAYMENT_QUOTE_CHANGED,WALLET_CORE_API_BAD_REQUEST.Details:
exchangeBaseUrlandrestrictScopeare mutually exclusive. Thepurse_expirationinpartialContractTermsmust be finite and in the future. When apeerPushDebitQuoteobtained from checkPeerPushDebitV2 is passed, an explicit expiration is required, and wallet-core rejects the request when it does not match the quote or when the coin selection, fees or the selected exchange changed since the quote was made.The
taler://pay-push/URI to hand to the receiver is not part of the response; it is available from the transaction (see getTransactionById) once the transaction is pending.
interface InitiatePeerPushDebitRequest {
exchangeBaseUrl?: string;
// Restrict the scope of funds that can be spent via the given
// scope info.
restrictScope?: ScopeInfo;
// Quote returned by checkPeerPushDebitV2.
peerPushDebitQuote?: string;
partialContractTerms: PartialPeerContractTerms;
}
interface PartialPeerContractTerms {
amount: AmountString;
summary: string;
icon_id?: string;
purse_expiration?: TalerProtocolTimestamp;
}
interface InitiatePeerPushDebitResponse {
exchangeBaseUrl: string;
pursePub: string;
mergePriv: string;
contractPriv: string;
transactionId: TransactionIdStr;
}
- confirmPeerPushCredit#
Accept an incoming peer push payment, after reviewing it with preparePeerPushCredit.
Request:
The request body must be a ConfirmPeerPushCreditRequest object.
Response:
On success, the result is an AcceptPeerPushPaymentResponse object. Confirmation is idempotent: confirming a transaction that already left the review state returns the same
transactionId.Side effects:
Confirms an incoming peer push payment; the wallet withdraws the funds from the purse over the network.
Expected errors:
The caller can handle the following errors inline:
WALLET_KYC_LIMIT_EXCEEDED,WALLET_EXCHANGE_TOS_NOT_ACCEPTED,WALLET_TRANSACTION_NOT_FOUND,WALLET_EXCHANGE_KEYS_NOT_ACCEPTED.
interface ConfirmPeerPushCreditRequest {
transactionId: string;
progressToken?: string;
}
interface AcceptPeerPushPaymentResponse {
transactionId: TransactionIdStr;
}
- checkPeerPullCredit#
Check fees for an outgoing peer pull payment, i.e. a payment request that this wallet creates for another wallet to pay.
Request:
The request body must be a CheckPeerPullCreditRequest object. Either
exchangeBaseUrlorrestrictScopemust be specified.Response:
On success, the result is a CheckPeerPullCreditResponse object.
Side effects:
May refresh the exchange’s key material over the network and writes denomination verification results.
Expected errors:
The caller can handle the following errors inline:
WALLET_NO_SUITABLE_EXCHANGE,WALLET_CORE_API_BAD_REQUEST.
interface CheckPeerPullCreditRequest {
// Require using this particular exchange for this operation.
exchangeBaseUrl?: string;
restrictScope?: ScopeInfo;
amount: AmountString;
progressToken?: string;
}
interface CheckPeerPullCreditResponse {
exchangeBaseUrl: string;
amountRaw: AmountString;
amountEffective: AmountString;
// Wallet-selected default expiration for the request.
defaultExpiration: TalerProtocolDuration;
// Number of coins that will be used; can be used by the UI to
// warn if excessively large.
numCoins: number;
}
- initiatePeerPullCredit#
Initiate an outgoing peer pull payment: create a payment request (invoice) that another wallet can pay.
Request:
The request body must be an InitiatePeerPullCreditRequest object.
Response:
On success, the result is an InitiatePeerPullCreditResponse object.
Side effects:
Creates an outgoing peer pull payment request transaction.
Expected errors:
The caller can handle the following errors inline:
WALLET_NO_SUITABLE_EXCHANGE,WALLET_KYC_LIMIT_EXCEEDED,WALLET_EXCHANGE_TOS_NOT_ACCEPTED,WALLET_CORE_API_BAD_REQUEST,WALLET_EXCHANGE_KEYS_NOT_ACCEPTED.Details:
The
taler://pay-pull/URI to hand to the payer is available from the transaction (see getTransactionById) once the transaction is in the appropriate state; thetalerUrifield of the response is deprecated because it is not necessarily valid yet.
interface InitiatePeerPullCreditRequest {
exchangeBaseUrl?: string;
partialContractTerms: PeerContractTerms;
progressToken?: string;
}
interface InitiatePeerPullCreditResponse {
// Taler URI for the other party to make the requested payment.
// Deprecated: not necessarily valid yet until the transaction is
// in the right state.
talerUri?: string;
transactionId: TransactionIdStr;
}
- preparePeerPullDebit#
Prepare for an incoming peer pull payment: another wallet requests to be paid by this wallet. The request is identified either by a
taler://pay-pull/URI received from the other party or by thetransactionIdof an existing peer-pull-debit transaction.Request:
The request body must be a PreparePeerPullDebitRequest object. Either
talerUriortransactionIdmust be specified.Response:
On success, the result is a PreparePeerPullDebitResponse object, carrying the contract terms and the amounts, so that the user can review the request before paying with confirmPeerPullDebit.
Side effects:
Fetches the contract and purse status from the exchange over the network and creates a peer pull debit transaction in dialog state.
Expected errors:
The caller can handle the following errors inline:
WALLET_PEER_CONTRACT_NOT_FOUND,WALLET_PEER_PULL_DEBIT_PURSE_GONE,WALLET_PEER_PULL_DEBIT_ALREADY_PAID,WALLET_PEER_PULL_PAYMENT_INSUFFICIENT_BALANCE,WALLET_TALER_URI_MALFORMED,WALLET_TRANSACTION_NOT_FOUND.
// Either talerUri or transactionId must be specified.
interface PreparePeerPullDebitRequest {
talerUri?: string;
transactionId?: string;
progressToken?: string;
}
interface PreparePeerPullDebitResponse {
contractTerms: PeerContractTerms;
amountRaw: AmountString;
amountEffective: AmountString;
transactionId: TransactionIdStr;
// State of the existing or newly created transaction.
txState: TransactionState;
exchangeBaseUrl: string;
scopeInfo: ScopeInfo;
// Deprecated: redundant field with bad name, will be removed soon.
amount: AmountString;
}
- confirmPeerPullDebit#
Accept an incoming peer pull payment (i.e. pay the other party), after reviewing the request with preparePeerPullDebit.
Request:
The request body must be a ConfirmPeerPullDebitRequest object.
Response:
On success, the result is an AcceptPeerPullPaymentResponse object. Confirmation is idempotent: confirming a transaction that already left the review state returns the same
transactionId.Side effects:
Pays the requested peer pull payment to the other wallet over the network.
Expected errors:
The caller can handle the following errors inline:
WALLET_PEER_PULL_PAYMENT_INSUFFICIENT_BALANCE,WALLET_TRANSACTION_NOT_FOUND.
interface ConfirmPeerPullDebitRequest {
transactionId: TransactionIdStr;
}
interface AcceptPeerPullPaymentResponse {
transactionId: TransactionIdStr;
}
- getMaxPeerPushDebitAmountread-only#
Query the maximum amount that can currently be sent via a peer push payment in the given currency.
Request:
The request body must be a GetMaxPeerPushDebitAmountRequest object.
Response:
On success, the result is a GetMaxPeerPushDebitAmountResponse object.
Details:
The result is the best per-exchange maximum across the exchanges known to the wallet for the currency (restricted to
restrictScopewhen given, and including the expected outputs of pending refresh operations).effectiveAmountis the total balance effect on the wallet andrawAmountthe amount the receiver would get after fees. When no exchange can serve the payment, zero amounts are returned andexchangeBaseUrlis omitted.
interface GetMaxPeerPushDebitAmountRequest {
currency: string;
// Preferred exchange to use for the p2p payment.
// Currently ignored by wallet-core; use restrictScope
// to constrain the exchanges that are considered.
exchangeBaseUrl?: string;
restrictScope?: ScopeInfo;
}
interface GetMaxPeerPushDebitAmountResponse {
effectiveAmount: AmountString;
rawAmount: AmountString;
exchangeBaseUrl?: string;
}
20.5.4.10. Exchange management#
These operations manage the set of exchanges known to the wallet, their terms of service and their key material.
- addExchange#
Add an exchange to the wallet, or force an update of the exchange entry.
Request:
The request arguments must be an AddExchangeRequest object.
Response:
On success, the result is an AddExchangeResponse object.
Side effects:
Adds or force-updates the exchange entry. The exchange’s keys and wire information are fetched over the network, and notifications are emitted.
Expected errors:
The caller can handle the following errors inline:
WALLET_TALER_URI_MALFORMED,WALLET_EXCHANGE_UNAVAILABLE,WALLET_EXCHANGE_SIGNATURE_INVALID,WALLET_CORE_API_BAD_REQUEST.Details:
The
uriis either an http(s) exchange base URL or ataler://add-exchange/URI. An http(s) URL must already be canonical, unlessallowCompletionis set; in that case the wallet tries to complete the URL as with completeExchangeBaseUrl and fails if completion is not possible. The wallet fetches the exchange’s key data before the request succeeds. Unlessephemeralis set, the exchange is marked as explicitly added by the user.
interface AddExchangeRequest {
// Either an http(s) exchange base URL or
// a taler://add-exchange/ URI.
uri?: string;
// Only ephemerally add the exchange.
ephemeral?: boolean;
// Allow passing incomplete URLs. The wallet will try to complete
// the URL and throw an error if completion is not possible.
allowCompletion?: boolean;
// Deprecated: start a forced exchange update with a separate
// updateExchangeEntry call instead.
forceUpdate?: boolean;
// Deprecated: use the uri field instead.
exchangeBaseUrl?: string;
// Correlates progress notifications and allows cancellation.
progressToken?: string;
}
interface AddExchangeResponse {
// Base URL of the exchange that was added to the wallet.
exchangeBaseUrl: string;
}
- listExchangesread-only#
List exchanges known to the wallet.
Request:
The request arguments must be a ListExchangesRequest object. Omitted filter fields do not restrict the result.
Response:
On success, the result is an ExchangesListResponse object.
interface ListExchangesRequest {
// Filter results to only include exchanges in the given scope.
filterByScope?: ScopeInfo;
// Filter results to only include exchanges
// with the given status.
filterByExchangeEntryStatus?: ExchangeEntryStatus;
// Filter results to only include exchanges with the
// given type.
filterByType?: ExchangeType;
}
type ExchangeType = "demo" | "prod";
interface ExchangesListResponse {
exchanges: ExchangeListItem[];
}
type ExchangeEntryStatus =
| "preset"
| "ephemeral"
| "used";
- listWithdrawalExchangeCandidatesread-only#
List exchanges suitable for presentation in a withdrawal chooser.
Request:
The request arguments must be a ListWithdrawalExchangeCandidatesRequest object. Omitted fields use their documented defaults.
Response:
On success, the result is a ListWithdrawalExchangeCandidatesResponse object.
Expected errors:
The caller can handle the following errors inline:
WALLET_CORE_API_BAD_REQUEST.Details:
Candidates are taken from the wallet’s exchange entries and from the builtin exchange list; ephemeral entries and entries with unknown currency are excluded. Demo and test exchanges are only included when
withDemoorwithTestare set. CombiningpresetOnlywithwithBuiltin: falseis rejected withWALLET_CORE_API_BAD_REQUEST. Exchanges recently used for a withdrawal are sorted first, andrecommendationReasonsstates why each candidate is suggested.
type ListWithdrawalExchangeCandidatesRequest =
GetDefaultExchangesRequest;
interface ListWithdrawalExchangeCandidatesResponse {
candidates: WithdrawalExchangeCandidate[];
}
interface WithdrawalExchangeCandidate {
// A taler://withdraw-exchange URI for the exchange.
talerUri: string;
exchangeBaseUrl: string;
currency: string;
currencySpec: CurrencySpecification;
exchangeEntryStatus: ExchangeEntryStatus;
exchangeUpdateStatus: ExchangeUpdateStatus;
source: ExchangeEntrySource;
recommendationReasons: ExchangeRecommendationReason[];
lastWithdrawal?: TalerPreciseTimestamp;
}
type ExchangeRecommendationReason =
| "preset"
| "user-added"
| "previous-withdrawal"
| "previously-used";
- getDefaultExchangesread-onlydeprecated#
This operation is deprecated. Use listWithdrawalExchangeCandidates instead.
List the default exchanges offered to the user for withdrawing.
Request:
The request arguments must be a GetDefaultExchangesRequest object, as for listWithdrawalExchangeCandidates.
Response:
On success, the result is a GetDefaultExchangesResponse object.
Expected errors:
The caller can handle the following errors inline:
WALLET_CORE_API_BAD_REQUEST.Details:
The result is a reduced view of the withdrawal exchange candidates, carrying only the withdrawal URI, currency and currency specification of each candidate.
interface GetDefaultExchangesRequest {
// Only return production exchanges from the builtin exchange list.
// Cannot be combined with withBuiltin: false.
presetOnly?: boolean;
// Include exchanges from the builtin list. Defaults to true.
withBuiltin?: boolean;
// Include demo exchanges from the builtin list. Defaults to false.
withDemo?: boolean;
// Include test exchanges from the builtin list. Defaults to false.
withTest?: boolean;
}
interface GetDefaultExchangesResponse {
defaultExchanges: {
// A taler://withdraw-exchange URI for the exchange.
talerUri: string;
// Currency offered by the exchange.
currency: string;
// Currency spec for the currency offered by the exchange.
currencySpec: CurrencySpecification;
}[];
}
- getExchangeEntryByUrlread-only#
Get the wallet’s exchange entry for an exchange base URL.
Request:
The request arguments must be a GetExchangeEntryByUrlRequest object.
Response:
On success, the result is a GetExchangeEntryByUrlResponse object, which is an alias for ExchangeListItem (see listExchanges).
Expected errors:
The caller can handle the following errors inline:
WALLET_EXCHANGE_ENTRY_NOT_FOUND.
// Info about an exchange entry in the wallet.
interface ExchangeListItem {
exchangeBaseUrl: string;
source?: ExchangeEntrySource;
masterPub: string | undefined;
// Master public keys this exchange URL used before its current
// key. The array is sorted and does not include masterPub.
legacyMasterPubs: string[];
// Set when the exchange changed its key set and the user has not
// confirmed the change yet. Operations that send money to the
// exchange or disclose coin authorizations are refused while this
// is present.
unconfirmedKeyChange?: ExchangeKeyChangeInfo;
currency: string;
paytoUris: string[];
tosStatus: ExchangeTosStatus;
exchangeEntryStatus: ExchangeEntryStatus;
exchangeUpdateStatus: ExchangeUpdateStatus;
ageRestrictionOptions: number[];
walletKycStatus?: ExchangeWalletKycStatus;
walletKycReservePub?: string;
walletKycAccessToken?: string;
walletKycUrl?: string;
// Threshold that we've requested to satisfy.
walletKycRequestedThreshold?: string;
// P2P payments are disabled with this exchange
// (e.g. because no global fees are configured).
peerPaymentsDisabled: boolean;
directDepositsDisabled: boolean;
// Set to true if this exchange doesn't charge any fees.
noFees: boolean;
// Most general scope that the exchange is a part of.
scopeInfo: ScopeInfo;
// Instructs wallets to use certain bank-specific language (for
// buttons) and/or other UI/UX customization for compliance with
// the rules of that bank.
bankComplianceLanguage?: string;
lastUpdateTimestamp: TalerPreciseTimestamp | undefined;
// Most recent successful withdrawal through this exchange.
lastWithdrawal?: TalerPreciseTimestamp;
// Information about the last error that occurred when trying
// to update the exchange info.
lastUpdateErrorInfo?: OperationErrorInfo;
// Currency spec for the currency offered by the exchange.
currencySpec: CurrencySpecification;
}
// An exchange that changed its key set, pending the user's
// confirmation. The wallet has already adopted the new key set, so
// the entry works and the older coins stay spendable; withdrawing is
// withheld until the change is confirmed.
interface ExchangeKeyChangeInfo {
// Master public key the exchange now uses, and the wallet now
// trusts.
currentMasterPub: string;
currentCurrency: string;
// Master public key the wallet's older funds were issued under.
supersededMasterPub: string;
supersededCurrency: string;
// Whether the new key set still advertises denominations the
// wallet holds coins of. False means the exchange does not offer
// to settle the older coins at all; true is only the exchange's
// claim, not proof of continuity.
sharesDenominations: boolean;
firstSeen: TalerPreciseTimestamp;
}
interface OperationErrorInfo {
error: TalerErrorDetail;
}
type ExchangeTosStatus =
| "pending"
| "proposed"
| "accepted"
| "missing-tos";
// How an exchange entry became known to the wallet.
type ExchangeEntrySource =
| "builtin"
| "user"
| "discovered"
| "unknown";
type ExchangeUpdateStatus =
| "initial"
| "initial-update"
| "suspended"
| "unavailable-update"
| "ready"
| "ready-update"
| "outdated-update";
interface GetExchangeEntryByUrlRequest {
exchangeBaseUrl: string;
}
type GetExchangeEntryByUrlResponse = ExchangeListItem;
- updateExchangeEntry#
Update an exchange entry.
Only starts updating the exchange entry. After this request finishes, it is not guaranteed that the exchange entry has been updated. Use notifications and the listExchanges request to check the status.
Request:
The request arguments must be an UpdateExchangeEntryRequest object.
Response:
On success, the result is an empty object.
Side effects:
Starts an update of the exchange entry: data is fetched over the network and notifications are emitted; completion is reported asynchronously.
Details:
Setting
forcestarts the update even when the entry was recently updated or the exchange is currently marked unavailable.If no exchange entry exists for
exchangeBaseUrlyet, a new entry is created and the update proceeds; the request does not fail for unknown base URLs. Failures of the update itself (for example the exchange being unreachable) are not reported as request errors but asynchronously: they surface via notifications and thelastUpdateErrorInfoof listExchanges.
interface UpdateExchangeEntryRequest {
exchangeBaseUrl: string;
// Force the update even if the entry was recently updated or
// the exchange is currently marked unavailable.
force?: boolean;
}
- getExchangeResourcesread-only#
Check whether the wallet still holds resources associated with an exchange.
Request:
The request arguments must be a GetExchangeResourcesRequest object.
Response:
On success, the result is a GetExchangeResourcesResponse object.
Details:
Resources are the coins and withdrawal groups (including internal withdrawals of peer transactions) associated with the exchange;
hasResourcesis true if any of them exist. Clients can use this to decide whether deleteExchange requires explicit user confirmation.
interface GetExchangeResourcesRequest {
exchangeBaseUrl: string;
}
interface GetExchangeResourcesResponse {
hasResources: boolean;
}
- completeExchangeBaseUrl#
Try to complete a partial URL into the canonical base URL of an exchange.
Request:
The request arguments must be a CompleteBaseUrlRequest object.
Response:
On success, the result is a CompleteBaseUrlResult object.
Side effects:
Probes candidate base URLs over the network until one validates as an exchange.
Details:
The wallet derives candidate base URLs from
urland probes them, returning the first candidate that answers like an exchange. A failure to complete is reported in-band via thestatusfield of the result, not with an error response:bad-syntaxwhen the URL is too malformed to be completed,bad-networkwhen no candidate could be reached andbad-exchangewhen the endpoint is reachable but is not an exchange. In the failure case,suggestionsmay list base URLs of exchanges known to the wallet that look similar to what was typed.
interface CompleteBaseUrlRequest {
url: string;
// Correlates progress notifications and allows cancellation.
progressToken?: string;
}
type CompleteBaseUrlResult =
| {
// ok: completion is a proper exchange
status: "ok";
// Completed exchange base URL, if completion was possible
completion: string;
}
| {
// bad-syntax: url is so badly malformed, it can't be completed
// bad-network: syntax okay, but exchange can't be reached
// bad-exchange: syntax and network okay, but not talking to
// an exchange
status: "bad-syntax" | "bad-network" | "bad-exchange";
// Error details in case status is not "ok"
error: TalerErrorDetail;
// Base URLs of exchanges known to the wallet whose host looks
// like what the user meant to type, most likely first.
// Absent when the wallet does not know anything similar.
suggestions?: string[];
};
- deleteExchange#
Delete an exchange and its associated resources.
Request:
The request arguments must be a DeleteExchangeRequest object.
Response:
On success, the result is an empty object.
Side effects:
Deletes the exchange and its associated resources.
Expected errors:
The caller can handle the following errors inline:
WALLET_EXCHANGE_ENTRY_USED.Details:
The operation fails with
WALLET_EXCHANGE_ENTRY_USEDwhen the exchange still has associated resources (see getExchangeResources), unlesspurgeis set. Some transactions related to the exchange (payments, peer payments and refreshes) are kept even when purging. Deleting an exchange that is not known to the wallet succeeds silently.
interface DeleteExchangeRequest {
exchangeBaseUrl: string;
// Delete the exchange even if it's in use.
purge?: boolean;
}
- purgeExchangeLegacyKeys#
Purge every non-current key set retained for an exchange URL.
Request:
The request arguments must be a PurgeExchangeLegacyKeysRequest object.
Response:
On success, the result is an empty object.
Side effects:
Deletes the retained non-current key sets of the exchange.
Expected errors:
The caller can handle the following errors inline:
WALLET_EXCHANGE_ENTRY_NOT_FOUND,WALLET_CORE_API_BAD_REQUEST.Details:
Removes the coins, denominations and other stored data issued under superseded master public keys of the exchange; withdrawals of purged coins are marked as legacy. The
currentMasterPubmust be the current master key observed by the client before confirming the purge: the operation fails atomically withWALLET_CORE_API_BAD_REQUESTif the exchange has changed keys since, so a key rotation between review and execution cannot turn the key the user just reviewed into another key that is silently purged.
interface PurgeExchangeLegacyKeysRequest {
exchangeBaseUrl: string;
// Current master key observed by the client before confirming the
// purge. The operation fails atomically if the exchange has
// changed keys since.
currentMasterPub: string;
}
- confirmExchangeKeyChange#
Confirm that the exchange’s changed key set is legitimate.
The wallet has already adopted the changed key set; this releases the operations that send money to the exchange, which are withheld until the user has had a chance to notice that the key changed.
Request:
The request arguments must be a ConfirmExchangeKeyChangeRequest object.
Response:
On success, the result is an empty object.
Side effects:
Records the user’s confirmation of the exchange’s changed keys and releases the withheld operations that send money to the exchange.
Expected errors:
The caller can handle the following errors inline:
WALLET_EXCHANGE_NO_KEY_CHANGE_PENDING,WALLET_EXCHANGE_KEY_CHANGE_MISMATCH.Details:
currentMasterPubmust be the master public key the exchange currently uses, so that a UI showing a stale key change cannot confirm a different one than the user was looking at.
interface ConfirmExchangeKeyChangeRequest {
exchangeBaseUrl: string;
// Master public key the exchange now uses. Required, so that a
// UI showing a stale key change cannot confirm a different one
// than the user was looking at.
currentMasterPub: string;
}
- setExchangeTosAccepted#
Mark the current version of the exchange’s terms of service as accepted by the user.
Request:
The request arguments must be an AcceptExchangeTosRequest object.
Response:
On success, the result is an empty object.
Side effects:
Records acceptance of the exchange’s terms of service.
Details:
The accepted version is the current ToS version observed by the wallet, as reported by getExchangeTos.
interface AcceptExchangeTosRequest {
exchangeBaseUrl: string;
}
- setExchangeTosForgotten#
Forget the acceptance of the exchange’s terms of service, marking them as not accepted.
Request:
The request arguments must be an AcceptExchangeTosRequest object (see setExchangeTosAccepted).
Response:
On success, the result is an empty object.
Side effects:
Clears the recorded acceptance of the exchange’s terms of service.
- getExchangeTos#
Get the current terms of service of an exchange.
Request:
The request arguments must be a GetExchangeTosRequest object.
Response:
On success, the result is a GetExchangeTosResult object.
Side effects:
Fetches the current terms of service from the exchange over the network and stores the new ETag in the exchange record.
Expected errors:
The caller can handle the following errors inline:
WALLET_EXCHANGE_ENTRY_NOT_FOUND.Details:
The wallet downloads the terms of service from the exchange, using
acceptedFormatandacceptLanguagefor content negotiation, and updates its stored current ToS version tag. If the exchange does not provide terms of service,tosStatusis"missing-tos"and the content fields carry placeholder values.
interface GetExchangeTosRequest {
exchangeBaseUrl: string;
// Acceptable content types for the ToS text, used for content
// negotiation with the exchange.
acceptedFormat?: string[];
// Preferred language for the ToS text.
acceptLanguage?: string;
// Correlates progress notifications and allows cancellation.
progressToken?: string;
}
interface GetExchangeTosResult {
// Markdown version of the current ToS.
content: string;
// Version tag of the current ToS.
currentEtag: string;
// Version tag of the last ToS that the user has accepted, if any.
acceptedEtag: string | undefined;
// Accepted content type
contentType: string;
// Language of the returned content. If missing, language is
// unknown.
contentLanguage: string | undefined;
// Available languages as advertised by the exchange.
tosAvailableLanguages: string[];
tosStatus: ExchangeTosStatus;
}
- getExchangeDetailedInforead-only#
Get detailed information about an exchange, including a timeline for the fees charged by the exchange.
Request:
The request arguments must be a GetExchangeDetailedInfoRequest object.
Response:
On success, the result is an ExchangeDetailedResponse object.
Expected errors:
The caller can handle the following errors inline:
WALLET_EXCHANGE_ENTRY_NOT_FOUND.Details:
The
denomFees,transferFeesandglobalFeesof the result are timelines: each FeeDescription covers the time range fromfromtountilduring which the fee applies.
interface GetExchangeDetailedInfoRequest {
exchangeBaseUrl: string;
}
interface ExchangeDetailedResponse {
exchange: ExchangeFullDetails;
}
interface ExchangeFullDetails {
exchangeBaseUrl: string;
currency: string;
paytoUris: string[];
auditors: ExchangeAuditor[];
wireInfo: WireInfo;
denomFees: DenomOperationMap<FeeDescription[]>;
transferFees: Record<string, FeeDescription[]>;
globalFees: FeeDescription[];
}
type DenomOperation = "deposit" | "withdraw" | "refresh" | "refund";
type DenomOperationMap<T> = { [op in DenomOperation]: T };
interface FeeDescription {
group: string;
from: AbsoluteTime;
until: AbsoluteTime;
fee?: AmountString;
}
interface WireInfo {
feesForType: WireFeeMap;
accounts: ExchangeWireAccount[];
}
type WireFeeMap = { [wireMethod: string]: WireFee[] };
// Wire fee for one wire method
interface WireFee {
// Fee for wire transfers.
wireFee: AmountString;
// Fees to close and refund a reserve.
closingFee: AmountString;
// Start date of the fee.
startStamp: TalerProtocolTimestamp;
// End date of the fee.
endStamp: TalerProtocolTimestamp;
// Signature made by the exchange master key.
sig: string;
}
- startExchangeWalletKyc#
Start the wallet KYC process at an exchange, requesting authorization to hold funds up to the given amount threshold.
Request:
The request arguments must be a StartExchangeWalletKycRequest object.
Response:
On success, the result is an empty object.
Side effects:
Starts the wallet KYC process at the exchange over the network; progress is reported via transactions and notifications.
Details:
The request only initiates the KYC process; the wallet then drives it in the background and reports status changes via notifications. If a KYC threshold of at least
amountwas already granted or is already being requested, the operation does nothing. Once started, the exchange entry is marked as used, as the wallet keeps an account at the exchange.
interface StartExchangeWalletKycRequest {
exchangeBaseUrl: string;
// Amount threshold that the KYC process should authorize.
amount: AmountString;
}
20.5.4.11. Bank accounts#
Bank accounts known to the wallet are used as targets for deposits and as a fallback when entering peer-to-peer payment information manually.
- listBankAccountsread-only#
List bank accounts known to the wallet from previous withdrawals.
Request:
The request must be a ListBankAccountsRequest object.
Response:
On success, the result is a ListBankAccountsResponse object.
Details:
When
currencyis specified, only accounts that support the currency are returned; accounts whose supported currencies are unknown are always included. Stored accounts whosepaytoUrican no longer be parsed are silently skipped.
interface ListBankAccountsRequest {
currency?: string;
}
interface ListBankAccountsResponse {
accounts: WalletBankAccountInfo[];
}
interface WalletBankAccountInfo {
bankAccountId: string;
paytoUri: string;
// Did we previously complete a KYC process for this bank account?
// Deprecated: the KYC may have been completed for one exchange
// but not for another.
kycCompleted: boolean;
// Currencies supported by the bank, if known.
currencies: string[] | undefined;
label: string | undefined;
}
- getBankAccountByIdread-only#
Get a known bank account by its identifier.
Request:
The request must be a GetBankAccountByIdRequest object.
Response:
On success, the result is a GetBankAccountByIdResponse object.
Expected errors:
The caller can handle the following errors inline:
WALLET_BANK_ACCOUNT_NOT_FOUND.
interface GetBankAccountByIdRequest {
bankAccountId: string;
}
type GetBankAccountByIdResponse = WalletBankAccountInfo;
- addBankAccount#
Add a bank account to the wallet’s list of known bank accounts.
Request:
The request must be an AddBankAccountRequest object.
Response:
On success, the result is an AddBankAccountResponse object.
Side effects:
Adds the bank account to the wallet’s database, or updates the existing account with the same
paytoUri. Abank-account-changenotification is emitted.Expected errors:
The caller can handle the following errors inline:
GENERIC_PAYTO_URI_MALFORMED,WALLET_BANK_ACCOUNT_NOT_FOUND.Details:
If an account with the same
paytoUriis already known, it is updated (the supported currencies are merged) and its identifier is returned. WhenreplaceBankAccountIdis specified, the account with that identifier is replaced and keeps its identifier; the request fails withWALLET_BANK_ACCOUNT_NOT_FOUNDwhen no such account exists.In all cases the stored account is rewritten with the values from the request, so updating or replacing an account resets its
kycCompletedflag tofalse.
interface AddBankAccountRequest {
// Payto URI of the bank account that should be added.
paytoUri: string;
// Human-readable label for the account.
label: string;
// Currencies supported by the bank (if known).
currencies?: string[] | undefined;
// Bank account that this new account should replace.
replaceBankAccountId?: string;
}
interface AddBankAccountResponse {
// Identifier of the added bank account.
bankAccountId: string;
}
- forgetBankAccount#
Remove a known bank account.
Request:
The request must be a ForgetBankAccountRequest object.
Response:
On success, the result is an empty object (EmptyObject).
Side effects:
Removes the bank account from the wallet’s database. A
bank-account-changenotification is emitted.Expected errors:
The caller can handle the following errors inline:
WALLET_BANK_ACCOUNT_NOT_FOUND.
interface ForgetBankAccountRequest {
bankAccountId: string;
}
20.5.4.12. Global currency management#
These operations manage the wallet’s configuration for a global currency: the auditors that the wallet trusts for a currency and the exchanges offering it, as well as the currency specification itself.
- listGlobalCurrencyExchangesread-only#
List the exchanges registered for global currencies.
Request:
This operation takes no arguments (an empty object).
Response:
On success, the result is a ListGlobalCurrencyExchangesResponse object.
interface ListGlobalCurrencyExchangesResponse {
exchanges: {
currency: string;
exchangeBaseUrl: string;
exchangeMasterPub: string;
}[];
}
- listGlobalCurrencyAuditorsread-only#
List the auditors the wallet trusts for global currencies.
Request:
This operation takes no arguments (an empty object).
Response:
On success, the result is a ListGlobalCurrencyAuditorsResponse object.
interface ListGlobalCurrencyAuditorsResponse {
auditors: {
currency: string;
auditorBaseUrl: string;
auditorPub: string;
}[];
}
- addGlobalCurrencyExchange#
Register an exchange for a global currency.
Request:
The request must be an AddGlobalCurrencyExchangeRequest object.
Response:
On success, the result is an empty object (EmptyObject).
Side effects:
Registers the exchange for the global currency in the wallet’s database. When the configuration changed, a
balance-changenotification is emitted.Details:
Adding an exchange that is already registered is a no-op. Currency information already known under the exchange’s own scope is copied to the global scope. The
exchangeBaseUrlmust be a canonicalized base URL (see canonicalizeBaseUrl).
interface AddGlobalCurrencyExchangeRequest {
currency: string;
exchangeBaseUrl: string;
exchangeMasterPub: string;
}
- removeGlobalCurrencyExchange#
Remove an exchange registered for a global currency.
Request:
The request must be a RemoveGlobalCurrencyExchangeRequest object.
Response:
On success, the result is an empty object (EmptyObject).
Side effects:
Removes the registration from the wallet’s database; removing the last exchange of a currency also removes the global currency information. When the configuration changed, a
balance-changenotification is emitted.Details:
Removing an exchange that is not registered is a no-op.
interface RemoveGlobalCurrencyExchangeRequest {
currency: string;
exchangeBaseUrl: string;
exchangeMasterPub: string;
}
- addGlobalCurrencyAuditor#
Register a trusted auditor for a global currency.
Request:
The request must be an AddGlobalCurrencyAuditorRequest object.
Response:
On success, the result is an empty object (EmptyObject).
Side effects:
Registers the auditor for the global currency in the wallet’s database. When the configuration changed, a
balance-changenotification is emitted.Details:
Adding an auditor that is already registered is a no-op. The
auditorBaseUrlmust be a canonicalized base URL (see canonicalizeBaseUrl).
interface AddGlobalCurrencyAuditorRequest {
currency: string;
auditorBaseUrl: string;
auditorPub: string;
}
- removeGlobalCurrencyAuditor#
Remove a trusted auditor for a global currency.
Request:
The request must be a RemoveGlobalCurrencyAuditorRequest object.
Response:
On success, the result is an empty object (EmptyObject).
Side effects:
Removes the registration from the wallet’s database. When the configuration changed, a
balance-changenotification is emitted.Details:
Removing an auditor that is not registered is a no-op.
interface RemoveGlobalCurrencyAuditorRequest {
currency: string;
auditorBaseUrl: string;
auditorPub: string;
}
- getCurrencySpecificationread-only#
Get the currency specification (input and rendering rules) for a currency scope.
Request:
The request must be a GetCurrencySpecificationRequest object.
Response:
On success, the result is a GetCurrencySpecificationResponse object.
Details:
The specification recorded for the given scope is returned. For the demonstration currencies
KUDOSandTESTKUDOS, a hard-coded specification is returned. When no specification is known for the scope, a default with two fractional digits derived from the currency name is returned.
interface GetCurrencySpecificationRequest {
scope: ScopeInfo;
}
interface GetCurrencySpecificationResponse {
currencySpecification: CurrencySpecification;
}
// Currency scope, discriminated on the "type" field.
type ScopeInfo =
| ScopeInfoGlobal
| ScopeInfoExchange
| ScopeInfoAuditor
| ScopeInfoExchangeLegacyKeys;
type ScopeInfoGlobal = {
type: ScopeType.Global;
currency: string;
};
type ScopeInfoExchange = {
type: ScopeType.Exchange;
currency: string;
url: string;
};
type ScopeInfoAuditor = {
type: ScopeType.Auditor;
currency: string;
url: string;
};
type ScopeInfoExchangeLegacyKeys = {
type: ScopeType.ExchangeLegacyKeys;
currency: string;
url: string;
// The superseded key the funds were issued under.
masterPub: string;
};
enum ScopeType {
Global = "global",
Exchange = "exchange",
Auditor = "auditor",
// Funds issued under a master public key the exchange has
// since replaced.
ExchangeLegacyKeys = "exchange-legacy-keys",
}
// Input and rendering rules for a currency (see DD51).
interface CurrencySpecification {
// Name of the currency.
name: string;
// How many digits the user may enter after the decimal
// separator.
num_fractional_input_digits: Integer;
// Number of fractional digits to render in normal font and
// size.
num_fractional_normal_digits: Integer;
// Number of fractional digits to render always, padding with
// zeros if needed.
num_fractional_trailing_zero_digits: Integer;
// Map of powers of 10 to alternative currency names / symbols;
// always has an entry under "0" with the base name, e.g.
// "0 => €" or "3 => k€".
alt_unit_names: { [log10: string]: string };
common_amounts?: AmountString[];
}
20.5.4.13. Tokens#
Token families represent discount tokens and subscription tokens obtained during merchant payments.
- listDiscountsread-only#
List discount tokens stored in the wallet. Listed tokens are grouped by token family. Only tokens that are within their validity period and not currently in use by a transaction are listed.
Request:
The request arguments must be a ListDiscountsRequest object. Omitted filter fields do not restrict the result.
Response:
On success, the result is a ListDiscountsResponse object.
interface ListDiscountsRequest {
// Filter by hash of token issue public key.
tokenIssuePubHash?: string;
// Filter by merchant base URL.
merchantBaseUrl?: string;
}
interface ListDiscountsResponse {
discounts: DiscountListDetail[];
}
interface DiscountListDetail {
// Hash of token family info.
tokenFamilyHash: string;
// Hash of token issue public key.
tokenIssuePubHash: string;
// URL of the merchant issuing the token.
merchantBaseUrl: string;
// Information about the merchant issuing the token.
merchantInfo?: MerchantInfo;
// Human-readable name for the token family.
name: string;
// Human-readable description for the token family.
description: string;
// Optional map from IETF BCP 47 language tags to localized descriptions.
descriptionI18n: any | undefined;
// Start time of the token's validity period.
validityStart: Timestamp;
// End time of the token's validity period.
validityEnd: Timestamp;
// Number of tokens available to use.
tokensAvailable: number;
}
interface MerchantInfo {
// The merchant's legal name of business.
name: string;
// Contact email address of the merchant.
email?: string;
// Website of the merchant.
website?: string;
// An optional base64-encoded product image.
logo?: ImageDataUrl;
// Business address of the merchant.
address?: Location;
// Jurisdiction for disputes; some typical location fields may be absent.
jurisdiction?: Location;
}
- deleteDiscount#
Delete all discount tokens of one token family from the wallet.
Request:
The request arguments must be a DeleteDiscountRequest object.
Response:
On success, the result is an empty object.
Side effects:
Deletes all discount tokens of the token family from the wallet database. If any token of the family is still in use by a transaction, nothing is deleted.
Expected errors:
The caller can handle the following errors inline:
WALLET_TOKENS_IN_USE.
interface DeleteDiscountRequest {
// Hash of token family info.
tokenFamilyHash: string;
}
- listSubscriptionsread-only#
List subscription tokens stored in the wallet. Listed tokens are grouped by token family. Only tokens that are within their validity period and not currently in use by a transaction are listed.
Request:
The request arguments must be a ListSubscriptionsRequest object, which has the same fields as ListDiscountsRequest.
Response:
On success, the result is a ListSubscriptionsResponse object.
type ListSubscriptionsRequest = ListDiscountsRequest;
interface ListSubscriptionsResponse {
subscriptions: SubscriptionListDetail[];
}
// Same as DiscountListDetail, but without a token count.
type SubscriptionListDetail = Omit<DiscountListDetail, "tokensAvailable">;
- deleteSubscription#
Delete all subscription tokens of one token family from the wallet.
Request:
The request arguments must be a DeleteSubscriptionRequest object.
Response:
On success, the result is an empty object.
Side effects:
Deletes all subscription tokens of the token family from the wallet database. If any token of the family is still in use by a transaction, nothing is deleted.
Expected errors:
The caller can handle the following errors inline:
WALLET_TOKENS_IN_USE.
interface DeleteSubscriptionRequest {
// Hash of token family info.
tokenFamilyHash: string;
}
20.5.4.14. Donau#
The donau (donation authority) collects donation receipts for the wallet user. These operations configure the donau and query donation statements.
- setDonau#
Set the donation authority for this wallet.
Request:
The request arguments must be a SetDonauRequest object.
Response:
On success, the result is an empty object.
Side effects:
Writes the donation authority configuration to the wallet database, replacing any previously configured authority.
Details:
The taxpayer ID is stored together with a salted hash of it (as defined in LSD0013) that is later used to submit and query donation receipts. Repeating the request with an unchanged
donauBaseUrlandtaxPayerIdis idempotent: the existing salt is kept.
interface SetDonauRequest {
donauBaseUrl: string;
taxPayerId: string;
}
- getDonauread-only#
Get the currently configured donation authority for this wallet.
Request:
This operation takes no arguments (an empty object).
Response:
On success, the result is a GetDonauResponse object. The
currentDonauInfofield is undefined if no donation authority has been configured.
interface GetDonauResponse {
currentDonauInfo:
| {
donauBaseUrl: string;
taxPayerId: string;
}
| undefined;
}
- getDonauStatements#
Get a list of donation statements for this wallet. Both donation statements for the currently configured donation authority as well as past configurations (if they exist) are returned.
Request:
The request arguments must be a GetDonauStatementsRequest object.
Response:
On success, the result is a GetDonauStatementsResponse object.
Side effects:
Submits all pending donation receipts to the respective donation authority over the network and marks them as submitted in the wallet database, emitting a balance-change notification, before the statements are fetched.
Details:
A statement is requested from every donation authority (or only from the one named by
donauBaseUrl, if given) for each year with submitted receipts; years for which the authority has not yet issued a statement contribute no entry to the result.
interface GetDonauStatementsRequest {
donauBaseUrl?: string;
}
interface GetDonauStatementsResponse {
statements: DonauStatementItem[];
}
interface DonauStatementItem {
total: AmountString;
year: number;
legalDomain: string;
uri: string;
donationStatementSig: EddsaSignatureString;
donauPub: EddsaPublicKeyString;
}
20.5.4.15. Contacts#
- addContact#
Add a contact to the wallet’s contact list. Contacts are identified by the pair of
aliasandaliasType; if a contact with the same alias and alias type already exists, it is updated.Request:
The request arguments are an AddContactRequest object.
Response:
On success, the result is an empty object.
Side effects:
Adds or updates the contact in the wallet’s contact list. After the contact list has changed, wallet-core emits a
contact-addednotification.
interface AddContactRequest {
// The contact to add or update.
contact: ContactEntry;
}
interface ContactEntry {
// Contact alias.
alias: string;
// Alias type.
aliasType: string;
// Mailbox URI.
mailboxBaseUri: string;
// Mailbox identity.
mailboxAddress: HashCodeString;
// The source of this contact, may be a URI.
source: string;
// The local petname of the contact.
petname: string;
}
- deleteContact#
Delete a contact from the wallet’s contact list.
Request:
The request arguments are a DeleteContactRequest object.
Response:
On success, the result is an empty object.
Side effects:
Deletes the contact from the wallet’s contact list and emits a
contact-deletednotification.Details:
Only the
aliasandaliasTypefields of the given contact are used to identify the contact to delete; the remaining fields are ignored. Deleting a contact that does not exist is not an error.
interface DeleteContactRequest {
// The contact to delete.
contact: ContactEntry;
}
- getContactsread-only#
Get all contacts from the wallet’s contact list.
Request:
This operation takes no arguments (an empty object).
Response:
On success, the result is a ContactListResponse object.
interface ContactListResponse {
// All contacts stored in the wallet.
contacts: ContactEntry[];
}
20.5.4.16. Mailbox#
The mailbox is used to receive taler:// URIs (for example payment
requests) from other wallet users.
- getMailboxread-only#
Get the mailbox configuration stored locally for a mailbox service. This operation only reads the wallet’s local database.
Request:
The request arguments are a MailboxBaseUrl object.
Response:
On success, the result is a GetMailboxResponse object. The
mailboxConfigurationfield is absent if the wallet has no mailbox configuration for the given base URL.
interface MailboxBaseUrl {
// Base URL of the mailbox service.
mailboxBaseUrl: string;
}
interface GetMailboxResponse {
// Locally stored configuration for the mailbox service, if any.
mailboxConfiguration?: MailboxConfiguration;
}
- initializeMailbox#
Create a new mailbox at a mailbox service: wallet-core generates fresh signing and encryption keys, registers the mailbox with the service and stores the resulting configuration locally.
Request:
The request arguments are a MailboxBaseUrl object.
Response:
On success, the result is the newly created MailboxConfiguration object.
Side effects:
Registers a new mailbox at the mailbox service over the network and stores the configuration and keys locally.
Expected errors:
The caller can handle the following errors inline:
WALLET_MAILBOX_UNAVAILABLE,GENERIC_FORBIDDEN,WALLET_RECEIVED_MALFORMED_RESPONSE.Details:
A fresh key pair is generated on every call, so each call creates a new mailbox identity at the service. The registration is made with an expiration one year in the future. If the mailbox service requires payment for the registration, the operation still succeeds and the returned configuration has
payUriset, which the client can use to pay for the registration.GENERIC_FORBIDDENindicates that the mailbox service refused the registration.WALLET_RECEIVED_MALFORMED_RESPONSEindicates that the service asked for payment but did not say how to pay.
interface MailboxConfiguration {
// Base URL of the mailbox service.
mailboxBaseUrl: string;
// Private EdDSA signing key of the mailbox.
privateKey: EddsaPrivateKeyString;
// Private HPKE encryption key of the mailbox.
privateEncryptionKey: string;
// Expiration of the current mailbox registration.
expiration: Timestamp;
// Mailbox address (hash of the public signing key).
hAddress: string;
// Set when the mailbox service requires payment to complete
// the registration.
payUri?: TalerUri;
}
- getMailboxMessageread-only#
Get the mailbox messages stored locally in the wallet.
Note that the TypeScript client library exposes this operation as
GetMailboxMessages(with a trailing “s”), while the operation name sent on the wire isgetMailboxMessage.Request:
This operation takes no arguments (an empty object).
Response:
On success, the result is a MailboxMessagesResponse object.
Details:
This operation only reads the wallet’s local database; use refreshMailbox to download new messages from the mailbox service.
interface MailboxMessagesResponse {
// Locally stored mailbox messages.
messages: MailboxMessageRecord[];
}
// Record metadata for mailbox messages.
interface MailboxMessageRecord {
// Origin mailbox.
originMailboxBaseUrl: string;
// Time of download.
downloadedAt: Timestamp;
// Taler URI in message.
talerUri: string;
}
- addMailboxMessage#
Store a mailbox message in the wallet’s local database. If a message with the same
originMailboxBaseUrlandtalerUrialready exists, itsdownloadedAttimestamp is updated.Request:
The request arguments are an AddMailboxMessageRequest object.
Response:
On success, the result is an empty object.
Side effects:
Stores the message in the wallet’s local database and emits a
mailbox-message-addednotification.
interface AddMailboxMessageRequest {
// The message to store.
message: MailboxMessageRecord;
}
- deleteMailboxMessage#
Delete a mailbox message from the wallet’s local database.
Request:
The request arguments are a DeleteMailboxMessageRequest object.
Response:
On success, the result is an empty object.
Side effects:
Deletes the message from the wallet’s local database and emits a
mailbox-message-deletednotification.Details:
The message is identified by the
originMailboxBaseUrlandtalerUrifields of the given message; thedownloadedAtfield is ignored. Deleting a message that does not exist is not an error; themailbox-message-deletednotification is emitted regardless.
interface DeleteMailboxMessageRequest {
// The message to delete.
message: MailboxMessageRecord;
}
- sendTalerUriMailboxMessage#
Send a
taler://URI to the mailbox of a contact. Wallet-core fetches the public keys of the recipient’s mailbox from the contact’s mailbox service, verifies that they match the contact’s mailbox address, encrypts the URI for the recipient and uploads it to the recipient’s mailbox.Request:
The request arguments are a SendTalerUriMailboxMessageRequest object.
Response:
On success, the result is an empty object.
Side effects:
Sends the
taler://URI as a message via the contact’s mailbox service over the network. Does not change local wallet state.Expected errors:
The caller can handle the following errors inline:
WALLET_MAILBOX_UNAVAILABLE.
interface SendTalerUriMailboxMessageRequest {
// The recipient contact.
contact: ContactEntry;
// The taler:// URI to send.
talerUri: string;
}
- refreshMailbox#
Download new messages from a mailbox service: messages are fetched in batches, decrypted with the mailbox’s private encryption key, stored in the wallet’s local database and deleted on the mailbox service.
Request:
The request arguments are a MailboxConfiguration object for the mailbox to refresh.
Response:
On success, the result is a MailboxMessageRecordsResponse object with the newly downloaded messages.
Side effects:
Downloads new messages from the mailbox service over the network, stores them in the wallet’s local database and deletes them on the service. A
mailbox-message-addednotification is emitted for each stored message.Expected errors:
The caller can handle the following errors inline:
WALLET_MAILBOX_UNAVAILABLE,WALLET_RECEIVED_MALFORMED_RESPONSE.Details:
The configuration of the mailbox service (message size and response limit) is fetched before the first batch. Each downloaded message is stored like in addMailboxMessage. Messages that cannot be decrypted are skipped. At most 100 batches are fetched in one call.
WALLET_RECEIVED_MALFORMED_RESPONSEindicates that the mailbox service returned an invalid response (invalid response limit, or a message list whose size is not a multiple of the advertised message size).
interface MailboxMessageRecordsResponse {
// Newly downloaded messages.
messages: MailboxMessageRecord[];
}
20.5.4.17. Aliases (taldir)#
Aliases map human-readable identifiers to wallet addresses via a taldir service, allowing senders to pay the wallet user without exchanging URIs out of band.
- registerAlias#
Initiate the registration of an alias with a taldir (directory) service. The alias (for example an e-mail address or a phone number) is associated with a target URI, typically the wallet’s mailbox URI. Unless the registration is already paid for, the service sends a challenge to the alias; the registration is completed with completeRegisterAlias once the user has received the challenge.
Request:
The request arguments are a TaldirRegistrationRequest object.
Response:
On success, the result is a TaldirRegistrationResponse: an empty object if a challenge was sent to the alias, or a TaldirAlreadyPaidResponse object if the registration already exists and is still paid for.
Side effects:
Requests the alias registration at the taldir service over the network; the service may require payment for the registration.
Expected errors:
The caller can handle the following errors inline:
WALLET_ALIAS_REGISTRATION_FAILED.
interface TaldirRegistrationRequest {
// Alias to register, in alias-type-specific format.
alias: string;
// Type of the alias, e.g. "email" or "sms".
aliasType: string;
// Target URI to associate with the alias.
targetUri: string;
// Base URL of the taldir service.
taldirBaseUrl: string;
// For how long the registration should last or be extended.
duration: RelativeTime;
}
type TaldirRegistrationResponse =
| TaldirAlreadyPaidResponse
| EmptyObject;
interface TaldirAlreadyPaidResponse {
// The remaining duration for which this registration is still
// paid for.
valid_for: RelativeTime;
}
- completeRegisterAlias#
Complete an alias registration started with registerAlias by answering the challenge that the taldir service sent to the alias.
Request:
The request arguments are a TaldirRegistrationCompletionRequest object.
Response:
On success, the result is an empty object.
Side effects:
Completes the pending alias registration at the taldir service by submitting the challenge response over the network.
Expected errors:
The caller can handle the following errors inline:
WALLET_ALIAS_REGISTRATION_FAILED,GENERIC_FORBIDDEN.Details:
Wallet-core derives the answer sent to the service as the hash of the
challengetogether with thetargetUrifrom the registration request, which protects the user against authorizing a concurrent registration of a different target URI.GENERIC_FORBIDDENindicates that the service rejected the answer to the challenge.
interface TaldirRegistrationCompletionRequest {
// Alias being registered.
alias: string;
// Type of the alias.
aliasType: string;
// Challenge received at the alias.
challenge: string;
// Base URL of the taldir service.
taldirBaseUrl: string;
// Target URI from the registration request.
targetUri: string;
}
- lookupAlias#
Look up the target URI registered for an alias at a taldir service.
Request:
The request arguments are a TaldirLookupRequest object.
Response:
On success, the result is a TaldirLookupResponse object. The
targetUrifield is absent if the alias is not registered, or if the service does not support the requested alias type.Side effects:
Queries the taldir directory service over the network; does not change wallet state.
Expected errors:
The caller can handle the following errors inline:
WALLET_ALIAS_REGISTRATION_FAILED.
interface TaldirLookupRequest {
// Alias to look up.
alias: string;
// Type of the alias.
aliasType: string;
// Base URL of the taldir service.
taldirBaseUrl: string;
}
interface TaldirLookupResponse {
// Target URI registered for the alias, if any.
targetUri?: string;
}
20.5.4.18. Database management#
These operations back up, restore, migrate and clear the wallet database.
- importDb#
Import a wallet database dump, replacing the current database contents.
Request:
The request arguments must be an ImportDbRequest object.
Response:
On success, the result is an empty object.
Side effects:
Replaces the entire contents of the wallet database with the imported dump.
Expected errors:
The caller can handle the following errors inline:
WALLET_DB_BACKEND_UNSUPPORTED,WALLET_CORE_API_BAD_REQUEST,WALLET_CORE_REQUEST_CANCELLED.Details:
The format of
dump(JSON or SQLite) is detected automatically. Adumpthat does not look like a valid wallet database dump is rejected withWALLET_CORE_API_BAD_REQUEST; if the active database backend cannot import the dump’s format, the request fails withWALLET_DB_BACKEND_UNSUPPORTED. WhenprogressTokenis set, progress is reported via notifications and the import can be cancelled with cancelProgressToken; a cancelled import fails withWALLET_CORE_REQUEST_CANCELLED. After a successful import, all in-memory caches (exchange, denomination and refresh-cost data) are cleared, and the imported records are used to recompute the derived transaction view.
interface ImportDbRequest {
dump?: any;
// Correlates progress notifications and allows cancellation.
progressToken?: string;
}
- exportDbread-only#
Export the wallet database’s contents to JSON.
Request:
This operation takes no arguments (an empty object).
Response:
On success, the result is an unspecified JSON value.
- exportDbToFile#
Export the database to a file. The target directory must already exist.
Request:
The request arguments must be an ExportDbToFileRequest object.
Response:
On success, the result is an ExportDbToFileResponse object.
Side effects:
Writes the database dump to a new file on the host filesystem.
Expected errors:
The caller can handle the following errors inline:
WALLET_DB_BACKEND_UNSUPPORTED.Details:
The request fails with
WALLET_DB_BACKEND_UNSUPPORTEDif the active database backend cannot export the database to a file.
interface ExportDbToFileRequest {
// Directory that the DB should be exported into.
directory: string;
// Stem of the exported DB filename. The final name will be
// ${directory}/${stem}.${extension}, where the extension depends
// on the used DB backend.
stem: string;
// Force the format of the export. Supported values on
// filesystem-capable hosts are "json" and "sqlite3"; if omitted,
// the host's default is "sqlite3".
forceFormat?: string;
}
interface ExportDbToFileResponse {
// Full path to the backup.
path: string;
}
- importDbFromFile#
Import the database from a JSON or SQLite file. Caution: this overrides existing data.
Request:
The request arguments must be an ImportDbFromFileRequest object.
Response:
On success, the result is an empty object.
Side effects:
Replaces the entire contents of the wallet database with the dump read from the given file.
Expected errors:
The caller can handle the following errors inline:
WALLET_DB_BACKEND_UNSUPPORTED,WALLET_CORE_API_BAD_REQUEST,WALLET_CORE_REQUEST_CANCELLED.Details:
The
pathmust end in.jsonor.sqlite3; other files are rejected withWALLET_CORE_API_BAD_REQUEST, as is a file that cannot be read. TheprogressTokenbehaves as for importDb.
interface ImportDbFromFileRequest {
// Full path to a .json or .sqlite3 backup.
path: string;
// Correlates progress notifications and allows cancellation.
progressToken?: string;
}
- migrateDatabase#
Explicitly migrate an IndexedDB-emulation wallet to the native SQLite schema. The operation is idempotent when the wallet is already native.
Request:
The request arguments must be a MigrateDatabaseRequest object.
Response:
On success, the result is a MigrateDatabaseResponse object.
Side effects:
Converts the wallet database to the native SQLite schema. The migration can be long-running; progress is reported via notifications when
progressTokenis set.Expected errors:
The caller can handle the following errors inline:
WALLET_DB_BACKEND_UNSUPPORTED,WALLET_DB_UNAVAILABLE,WALLET_CORE_REQUEST_CANCELLED.Details:
When the wallet already uses the native SQLite schema, the request succeeds with
migratedset to false. The optionalprogressTokencorrelates progress notifications and allows cancellation via cancelProgressToken. If the migration itself fails, the request fails withWALLET_DB_UNAVAILABLEand the existing (IndexedDB) database remains active; a cancelled migration fails withWALLET_CORE_REQUEST_CANCELLED.
interface MigrateDatabaseRequest {
// Enables progress correlation and cancellation through
// cancelProgressToken.
progressToken?: string;
}
interface MigrateDatabaseResponse {
// Whether this request changed the active database backend.
migrated: boolean;
// Database backend active after the request.
databaseBackend: WalletDatabaseBackend;
}
type WalletDatabaseBackend = "indexeddb" | "sqlite";
- clearDb#
Dangerously clear the whole wallet database.
Request:
This operation takes no arguments (an empty object).
Response:
On success, the result is an empty object.
Side effects:
Irreversibly deletes the entire wallet database.
Details:
In addition to the database contents, all in-memory caches and the recorded flight records are cleared, and the background task scheduler is reloaded.
- recycle#
Export a backup, clear the database and re-import it.
This operation is declared but not implemented yet: every request currently fails with
GENERIC_FEATURE_NOT_IMPLEMENTED.Request:
This operation takes no arguments (an empty object).
Response:
On success, the result is an empty object.
Side effects:
None. The operation is declared but not implemented yet and always fails with
GENERIC_FEATURE_NOT_IMPLEMENTED.
20.5.4.19. Data validation and conversion#
Utility operations to validate and convert between data formats used by the front-ends.
- validateIbanread-only#
Validate an International Bank Account Number (IBAN) according to ISO 13616, including the country-specific length and the checksum.
Request:
The request must be a ValidateIbanRequest object.
Response:
On success, the result is a ValidateIbanResponse object.
interface ValidateIbanRequest {
iban: string;
}
interface ValidateIbanResponse {
valid: boolean;
}
- canonicalizeBaseUrlread-only#
Canonicalize a base URL the way wallet-core does for exchange and auditor base URLs.
Request:
The request must be a CanonicalizeBaseUrlRequest object.
Response:
On success, the result is a CanonicalizeBaseUrlResponse object.
Details:
An
https://scheme is prepended when the URL has no scheme, a trailing slash is appended to the path when missing, and any query and fragment are removed.
interface CanonicalizeBaseUrlRequest {
url: string;
}
interface CanonicalizeBaseUrlResponse {
url: string;
}
- convertIbanAccountFieldToPaytoread-only#
Convert user input for a bank account number into an IBAN payto URI.
Request:
The request must be a ConvertIbanAccountFieldToPaytoRequest object.
Response:
On success, the result is a ConvertIbanAccountFieldToPaytoResponse object.
Details:
Dashes and spaces are stripped from the input. For
HUF, the input is treated as a Hungarian BBAN and converted to an IBAN (a developer experiment enables the same conversion for Swiss BBANs); for other currencies, the input must be a valid IBAN. When the input cannot be converted,okisfalse.
interface ConvertIbanAccountFieldToPaytoRequest {
value: string;
currency: string;
}
type ConvertIbanAccountFieldToPaytoResponse =
| { ok: true; type: "iban" | "bban"; paytoUri: string }
| { ok: false };
- convertIbanPaytoToAccountFieldread-only#
Convert an IBAN payto URI into the account number representation expected by the target country’s banking interfaces.
Request:
The request must be a ConvertIbanPaytoToAccountFieldRequest object.
Response:
On success, the result is a ConvertIbanPaytoToAccountFieldResponse object.
Details:
Hungarian IBANs are converted to the domestic BBAN form (a developer experiment enables the same conversion for Swiss IBANs); all other IBANs are returned unchanged. An error is thrown when
paytoUriis not a valid payto URI.
interface ConvertIbanPaytoToAccountFieldRequest {
paytoUri: string;
}
interface ConvertIbanPaytoToAccountFieldResponse {
type: "iban" | "bban";
value: string;
}
- getBankingChoicesForPaytoread-only#
Get banking applications or websites that can execute the given payto URI.
Request:
The request must be a GetBankingChoicesForPaytoRequest object.
Response:
On success, the result is a GetBankingChoicesForPaytoResponse object.
Details:
Currently, choices are only returned for the
KUDOSdemonstration currency (links to the demonstrator bank’s website and app); the list is empty when the payto URI carries no amount or no choice is known for the currency. An error is thrown whenpaytoUriis not a valid payto URI.
interface GetBankingChoicesForPaytoRequest {
paytoUri: string;
}
interface GetBankingChoicesForPaytoResponse {
choices: BankingChoiceSpec[];
}
interface BankingChoiceSpec {
label: string;
type: "link";
uri: string;
}
- getQrCodesForPaytoread-onlydeprecated#
This operation is deprecated. Consult the withdrawal transaction details instead.
Get QR code representations of a payto URI, for example to let the user scan the code with a banking app.
Request:
The request must be a GetQrCodesForPaytoRequest object.
Response:
On success, the result is a GetQrCodesForPaytoResponse object.
Details:
All applicable QR code specifications are returned (an EPC QR code and/or a Swiss QR bill); the list is empty when none applies to the given payto URI.
interface GetQrCodesForPaytoRequest {
paytoUri: string;
}
interface GetQrCodesForPaytoResponse {
codes: QrCodeSpec[];
}
// Specification of a QR code that includes payment information.
interface QrCodeSpec {
// Type of the QR code. Depending on the type, different
// visual styles might be applied.
type: SupportedBankQr;
// Content of the QR code that should be rendered.
qrContent: string;
}
type SupportedBankQr = "epc-qr" | "spc";
20.5.4.20. Diagnostics#
- getDiagnosticsread-only#
Get a diagnostics report about the state of the wallet, serialized as a string in the requested format.
Request:
The request arguments must be a GetDiagnosticsRequest object.
Response:
On success, the result is a GetDiagnosticsResponse: the diagnostics report serialized as a string.
Expected errors:
The caller can handle the following errors inline:
WALLET_CORE_API_BAD_REQUEST.Details:
The report is privacy-scrubbed: transaction identifiers are replaced by synthetic labels. It contains the wallet-core version, the database backend with record counts, the known exchanges, coins, bank accounts and the newest transactions (at most
transactionLimitof them). TheWALLET_CORE_API_BAD_REQUESTerror is raised whentransactionLimitis not a non-negative safe integer smaller thanNumber.MAX_SAFE_INTEGER.
interface GetDiagnosticsRequest {
// Serialized output format. Defaults to JSON.
format?: DiagnosticsFormat;
// Maximum number of newest transactions to include. Defaults to 100.
transactionLimit?: number;
// Information supplied by the wallet frontend invoking wallet-core.
frontendInfo?: DiagnosticsFrontendInfo;
}
type DiagnosticsFormat = "json" | "yaml";
interface DiagnosticsFrontendInfo {
name: string;
version: string;
platform?: string;
}
// A serialized diagnostics report in the requested format, returned
// as a string so that clients can save it without depending on the
// report's internal schema.
type GetDiagnosticsResponse = string;
- getActiveTasksread-only#
Get the wallet’s currently active background tasks and their retry state.
Request:
This operation takes no arguments (an empty object).
Response:
On success, the result is a GetActiveTasksResponse object.
Details:
Tasks are wallet-core’s background retry loops, for example for pending withdrawals or payments.
firstTryandnextTrygive the time of the first attempt and of the next scheduled retry;lastErroris the error of the most recent attempt, if any.
interface GetActiveTasksResponse {
tasks: ActiveTask[];
}
interface ActiveTask {
taskId: string;
transaction?: TransactionIdStr | undefined;
firstTry?: AbsoluteTime | undefined;
nextTry?: AbsoluteTime | undefined;
retryCounter?: number | undefined;
lastError?: TalerErrorDetail | undefined;
}
20.5.4.21. Testing and debugging#
These operations are only meant for integration tests and developer experiments. They are not part of the API surface a production front-end should rely on.
- applyDevExperiment#
Apply a developer experiment, specified as a
taler://dev-experiment/URI, to the current wallet state. This allows UI developers and testers to play around without an elaborate test environment. Dev mode must be active in the wallet.Request:
The request must be an ApplyDevExperimentRequest object.
Response:
On success, the result is an empty object.
Side effects:
Applies arbitrary changes to the wallet’s state and database, depending on the experiment.
interface ApplyDevExperimentRequest {
devExperimentUri: string;
}
- testingGetSampleTransactionsread-only#
Get sample transactions for UI development. Currently always returns an empty transaction list.
Request:
This operation takes no arguments (an empty object).
Response:
On success, the result is a TransactionsResponse object.
- withdrawTestkudos#
Make a withdrawal of
TESTKUDOS:10from the test deployment at test.taler.net (exchangehttps://exchange.test.taler.net/via the corebank API athttps://bank.test.taler.net/).Request:
This operation takes no arguments (an empty object).
Response:
On success, the result is a WithdrawTestBalanceResult object.
Side effects:
Performs a real withdrawal at the test deployment over the network and creates a withdrawal transaction in the wallet.
interface WithdrawTestBalanceResult {
// Transaction ID of the newly created withdrawal transaction.
transactionId: TransactionIdStr;
// Account of the user registered for the withdrawal.
accountPaytoUri: string;
}
- withdrawTestBalance#
Make a withdrawal on a test deployment of the exchange and corebank.
Request:
The request must be a WithdrawTestBalanceRequest object.
Response:
On success, the result is a WithdrawTestBalanceResult object.
Side effects:
Registers a random bank user and performs a real withdrawal at the given test deployment over the network; creates a withdrawal transaction in the wallet.
Details:
The operation registers a random bank user via the corebank API, creates a withdrawal operation for the requested amount, accepts the resulting withdrawal URI as a bank-integrated withdrawal at the given exchange, and finally confirms the withdrawal operation at the bank.
interface WithdrawTestBalanceRequest {
// Amount to withdraw.
amount: AmountString;
// Corebank API base URL.
corebankApiBaseUrl: string;
// Exchange to use for withdrawal.
exchangeBaseUrl: string;
// Force the usage of a particular denomination selection.
// Only useful for testing.
forcedDenomSel?: ForcedDenomSel;
// If set to true, treat the account created during
// the withdrawal as a foreign withdrawal account.
useForeignAccount?: boolean;
}
interface ForcedDenomSel {
denoms: {
value: AmountString;
count: number;
}[];
}
- runIntegrationTest#
Run a simple integration test on a test deployment of the exchange and merchant: withdraw
amountToWithdrawvia the corebank API, spendamountToSpendat the merchant, and then exercise a refund: withdraw a second, fixed amount (18in the currency ofamountToSpend), pay7, refund6of it and pay another3. The operation waits for all involved transactions (including refreshes) to reach a final state before returning.Request:
The request must be an IntegrationTestArgs object.
Response:
On success, the result is an empty object.
Side effects:
Performs real withdrawals, payments and a refund at the test deployment over the network.
interface IntegrationTestArgs {
exchangeBaseUrl: string;
corebankApiBaseUrl: string;
merchantBaseUrl: string;
merchantAuthToken?: string;
amountToWithdraw: AmountString;
amountToSpend: AmountString;
}
- runIntegrationTestV2#
Run an integration test on a test deployment of the exchange and merchant. The test withdraws a fixed amount in the exchange’s currency and then exercises payments, a refund, peer-to-peer push and pull payments, and a deposit to a bank account.
Request:
The request must be an IntegrationTestV2Args object.
Response:
On success, the result is an empty object.
Side effects:
Performs real withdrawals, payments, a refund, peer-to-peer payments and a deposit at the test deployment over the network.
interface IntegrationTestV2Args {
exchangeBaseUrl: string;
corebankApiBaseUrl: string;
merchantBaseUrl: string;
merchantAuthToken?: string;
}
- dumpCoinsread-only#
Dump all coins of the wallet in a simple JSON format.
Request:
This operation takes no arguments (an empty object).
Response:
On success, the result is a CoinDumpJson object.
interface CoinDumpJson {
coins: Array<{
// The coin's denomination's public key.
denomPub: DenominationPubKey;
// Hash of denom_pub.
denomPubHash: string;
// Value of the denomination (without any fees).
denomValue: string;
// Public key of the coin.
coinPub: string;
// Base URL of the exchange for the coin.
exchangeBaseUrl: string;
// Public key of the parent coin.
// Only present if this coin was obtained via refreshing.
refreshParentCoinPub: string | undefined;
// Public key of the reserve for this coin.
// Only present if this coin was obtained via withdrawal.
withdrawalReservePub: string | undefined;
// Status of the coin.
coinStatus: CoinStatus;
// Information about the age restriction.
ageCommitmentProof: AgeCommitmentProof | undefined;
history: WalletCoinHistoryItem[];
}>;
}
type CoinStatus =
// Withdrawn and never shown to anybody.
| "fresh"
// Coin was lost as the denomination is not usable anymore.
| "denom-loss"
// Fresh, but marked as suspended, thus won't be used for spending.
| "fresh-suspended"
// A coin that has been spent and refreshed.
| "dormant";
type WalletCoinHistoryItem =
| {
type: "withdraw";
transactionId: TransactionIdStr;
}
| {
type: "spend";
transactionId: TransactionIdStr;
amount: AmountString;
}
| {
type: "refresh";
transactionId: TransactionIdStr;
amount: AmountString;
}
| {
type: "recoup";
transactionId: TransactionIdStr;
amount: AmountString;
}
| {
type: "refund";
transactionId: TransactionIdStr;
amount: AmountString;
};
- testCryptoread-only#
Test the crypto worker by hashing a fixed test string.
Request:
This operation takes no arguments (an empty object).
Response:
On success, the result is an unspecified JSON value.
- testPay#
Make a test payment using a test deployment of the exchange and merchant. Creates an order for
amountwith the givensummaryat the merchant and pays it.Request:
The request must be a TestPayArgs object.
Response:
On success, the result is a TestPayResult object.
Side effects:
Creates an order and makes a real payment at the test merchant over the network.
interface TestPayArgs {
merchantBaseUrl: string;
merchantAuthToken?: string;
amount: AmountString;
summary: string;
forcedCoinSel?: ForcedCoinSel;
}
// Forced coin selection for deposits/payments.
interface ForcedCoinSel {
coins: {
value: AmountString;
contribution: AmountString;
}[];
}
interface TestPayResult {
// Number of coins used for the payment.
numCoins: number;
}
- setCoinSuspended#
Set a coin as (un-)suspended. Suspended coins won’t be used for payments.
Request:
The request must be a SetCoinSuspendedRequest object.
Response:
On success, the result is an empty object.
Side effects:
Marks the coin as (un-)suspended; suspended coins are excluded from payments.
Details:
Only fresh coins can be suspended, and only suspended coins can be un-suspended; requesting any other status transition is a no-op. An unknown
coinPubis silently ignored (a warning is logged). Suspension updates the coin availability counters of the denomination accordingly.
interface SetCoinSuspendedRequest {
coinPub: string;
suspended: boolean;
}
- forceRefresh#
Force a refresh on coins where it would not be necessary. Creates a manual refresh group for the given coins.
Request:
The request must be a ForceRefreshRequest object.
Response:
On success, the result is an empty object.
Side effects:
Refreshes the given coins at the exchange over the network even where a refresh would not be necessary; creates refresh transactions.
Details:
The request fails if
refreshCoinSpecsis empty or names a coin that is unknown to the wallet. Each coin is refreshed for its full denomination value, unless a smalleramountis given.
interface ForceRefreshRequest {
refreshCoinSpecs: RefreshCoinSpec[];
}
interface RefreshCoinSpec {
coinPub: string;
// Amount to refresh; defaults to the coin's denomination value.
amount?: AmountString;
}
- testingWaitTransactionsFinalread-only#
Wait until all transactions are in a final state. The operation blocks until this condition is met or the wait fails, for example when the request is cancelled.
Request:
This operation takes no arguments (an empty object).
Response:
On success, the result is an empty object.
- testingWaitRefreshesFinalread-only#
Wait until all refresh transactions are in a final state. The operation blocks until this condition is met or the wait fails, for example when the request is cancelled.
Request:
This operation takes no arguments (an empty object).
Response:
On success, the result is an empty object.
- testingWaitTransactionStateread-only#
This operation is a legacy alias of waitTransactionState. It waits until a transaction is in a particular state and has the same behavior and payloads; the legacy type names TestingWaitTransactionRequest and TestingWaitTransactionStateResponse are aliases of WaitTransactionStateRequest and WaitTransactionStateResponse, respectively. The operation blocks until the transaction reaches the target state or the wait fails or times out.
Request:
The request must be a WaitTransactionStateRequest object.
Response:
On success, the result is a WaitTransactionStateResponse object.
- testingWaitExchangeStateread-only#
Wait until an exchange entry is in a particular state. Currently, only the wallet KYC status of the exchange entry can be waited on. The operation blocks until this condition is met or the wait fails, for example when the request is cancelled.
Request:
The request must be a TestingWaitExchangeStateRequest object.
Response:
On success, the result is an empty object.
interface TestingWaitExchangeStateRequest {
exchangeBaseUrl: string;
walletKycStatus?: ExchangeWalletKycStatus;
}
type ExchangeWalletKycStatus =
| "done"
// Wallet needs to request KYC status.
| "legi-init"
// User requires KYC or AML.
| "legi";
- testingWaitExchangeReady#
Wait until an exchange entry is ready. Returns an error if updating the exchange failed.
Request:
The request must be a TestingWaitExchangeReadyRequest object.
Response:
On success, the result is an empty object.
Side effects:
May trigger an update of the exchange entry over the network, for example when
forceUpdateis set.
interface TestingWaitExchangeReadyRequest {
exchangeBaseUrl: string;
// Do not stop waiting even when the exchange is
// in an error state.
noBail?: boolean;
// Force waiting until an update really happened.
forceUpdate?: boolean;
// Only consider the exchange as ready if the
// next auto-refresh is scheduled for the future.
waitAutoRefresh?: boolean;
}
- testingWaitTasksDoneread-only#
Wait until all pending tasks of the wallet are done. The operation blocks until this condition is met or the wait fails, for example when the request is cancelled.
Request:
This operation takes no arguments (an empty object).
Response:
On success, the result is an empty object.
- testingWaitBalanceread-only#
Wait until a balance has reached the desired value. Waits until the material balance in the currency of
amountequalsamount; onlytype"material"is currently supported. The operation blocks until this condition is met or the wait fails, for example when the request is cancelled.Request:
The request must be a TestingWaitBalanceRequest object.
Response:
On success, the result is an empty object.
interface TestingWaitBalanceRequest {
type: "material" | "available";
amount: AmountString;
}
- testingGetDbStatsread-only#
Get database statistics. The returned statistics are specific to the database backend in use.
Request:
This operation takes no arguments (an empty object).
Response:
On success, the result is an unspecified JSON value.
- testingSetTimetravel#
Add an offset to the wallet’s internal time.
Request:
The request must be a TestingSetTimetravelRequest object.
Response:
On success, the result is an empty object.
Side effects:
Offsets the wallet’s internal clock, affecting all time-based logic of the wallet.
interface TestingSetTimetravelRequest {
// Offset added to the wallet's internal time, in milliseconds.
offsetMs: number;
}
- testingGetDenomStatsread-only#
Get statistics about the denominations of an exchange known to the wallet.
Request:
The request must be a TestingGetDenomStatsRequest object.
Response:
On success, the result is a TestingGetDenomStatsResponse object.
interface TestingGetDenomStatsRequest {
exchangeBaseUrl: string;
}
interface TestingGetDenomStatsResponse {
// Denominations known to the wallet for the exchange.
numKnown: number;
// Denominations currently offered by the exchange.
numOffered: number;
// Denominations that are not usable anymore.
numLost: number;
}
- testingRecoverCoins#
Follow the refresh/link recovery chain for coins at one exchange.
Request:
The request must be a TestingRecoverCoinsRequest object.
Response:
On success, the result is a TestingRecoverCoinsResponse object.
Side effects:
Scans the exchange for coins belonging to the wallet over the network and re-claims the coins it finds, creating transactions and emitting notifications.
interface TestingRecoverCoinsRequest {
exchangeBaseUrl: string;
// Start with fresh coins by default.
// Unfinished recovery always resumes.
onlyFresh?: boolean;
progressToken?: string;
}
interface TestingRecoverCoinsResponse {
exchangeBaseUrl: string;
progressToken: string;
// False when a coin or residual refresh remains unfinished.
complete: boolean;
// Histories processed during this invocation.
numChecked: number;
numDiscovered: number;
numQueued: number;
// Newly imported coins that are now spendable,
// including residual refreshes.
numRecovered: number;
// Cumulative for a resumed recovery; excludes existing coins,
// spent ancestors, fees and pending refreshes.
recoveredAmount: AmountString;
issues: CoinRecoveryIssue[];
}
interface CoinRecoveryIssue {
coinPub: string;
refreshCommitment?: string;
reason:
| "missing-recovery-data"
| "missing-denomination"
| "invalid-history"
| "commitment-mismatch"
| "request-failed"
| "local-data-changed"
| "refresh-incomplete"
| "coin-unavailable";
description: string;
}
- testingCheckCoins#
Validate exchange coin histories and compare balances of unspent coins against the exchange’s view.
Request:
The request must be a TestingCheckCoinsRequest object.
Response:
On success, the result is a TestingCheckCoinsResponse object.
Side effects:
Queries the coin history from the exchange over the network for every checked coin.
interface TestingCheckCoinsRequest {
// Canonicalized before selecting coins.
// Only this exchange is contacted.
exchangeBaseUrl: string;
// Default true: check only fresh coins. False validates every coin
// status, comparing denomination value only for fresh or
// suspended-fresh coins.
onlyFresh?: boolean;
}
interface TestingCheckCoinsResponse {
exchangeBaseUrl: string;
// Denomination value of fresh coins under the exchange's current
// master key in the initial snapshot. Null if local data is
// unavailable.
expectedMaterialBalance: AmountString | null;
// Verified remaining exchange balance of those same coins. Null
// if any relevant history could not be verified or the material
// balance changed during the check; never a partial total.
actualMaterialBalance: AmountString | null;
// Coins selected by the exchange and onlyFresh filter
// in the initial snapshot.
numCoins: number;
// Validated histories with stable coin data,
// including balance mismatches.
numChecked: number;
// Balance differences, invalid exchange histories,
// and unavailable coin data.
issues: TestingCheckCoinsIssue[];
}
interface TestingCheckCoinsIssue {
coinPub: string;
denomPubHash: string;
category: "mismatch" | "error" | "incomplete";
reason:
| "balance-difference"
| "invalid-history"
| "request-failed"
| "missing-local-data"
| "local-data-changed";
description: string;
expected?: Record<string, string | number | boolean>;
actual?: Record<string, string | number | boolean>;
// On balance differences: exchange history in offset order,
// including credits.
exchangeOperations?: Array<
[operation: CoinSpendHistoryItem["type"], amount: AmountString]
>;
}
- testingPingread-only#
Do nothing. Can be used to check that wallet-core is alive and responding to requests.
Request:
This operation takes no arguments (an empty object).
Response:
On success, the result is an empty object.
- testingGetReserveHistory#
Fetch the history of a reserve from the exchange. The reserve must be known to the wallet, as the request to the exchange is signed with the reserve’s private key.
Request:
The request must be a TestingGetReserveHistoryRequest object.
Response:
On success, the result is an unspecified JSON value with the reserve history as returned by the exchange.
Side effects:
Queries the reserve history from the exchange over the network.
interface TestingGetReserveHistoryRequest {
reservePub: string;
exchangeBaseUrl: string;
}
- testingResetAllRetries#
Reset all task/transaction retries, resulting in an immediate re-try of all pending operations.
Request:
This operation takes no arguments (an empty object).
Response:
On success, the result is an empty object.
Side effects:
Resets the retry backoff of all tasks and transactions, causing immediate retries and thus network activity.
- testingWaitWalletKycread-only#
Wait for the wallet KYC process at an exchange. With
passedset to true, waits until KYC has been passed for at least the givenamount; otherwise already returns when legitimization is required. The operation blocks until this condition is met or the wait fails, for example when the request is cancelled.Request:
The request must be a TestingWaitWalletKycRequest object.
Response:
On success, the result is an empty object.
interface TestingWaitWalletKycRequest {
exchangeBaseUrl: string;
amount: AmountString;
// Do we wait for the KYC to be passed (true),
// or do we already return if legitimization is
// required (false).
passed: boolean;
}
- testingPlanMigrateExchangeBaseUrl#
Enable migration from an old exchange base URL to a new exchange base URL. The plan is only kept in memory (not persisted). The actual migration is applied on the next exchange update when either the exchange advertises the new base URL, or downloading keys from the old base URL fails while the new base URL is reachable and advertises itself as its own base URL.
Request:
The request must be a TestingPlanMigrateExchangeBaseUrlRequest object.
Response:
On success, the result is an empty object.
Side effects:
Enables a pending exchange base URL migration, which is applied once the exchange advertises the new base URL.
interface TestingPlanMigrateExchangeBaseUrlRequest {
oldExchangeBaseUrl: string;
newExchangeBaseUrl: string;
}
- testingRunFixup#
Run a named database fixup that repairs records in the wallet database. Fails if no fixup with the given
idexists.Request:
The request must be a RunFixupRequest object.
Response:
On success, the result is an empty object.
Side effects:
Runs a database fixup that modifies stored data.
interface RunFixupRequest {
// Name of the fixup to run.
id: string;
}
- testingGetFlightRecordsread-only#
Get the wallet’s flight records: records of exceptional events observed while communicating with an exchange (such as a coin reported as gone during a refresh melt, or a withdrawal requiring redenomination), kept for post-mortem debugging.
Request:
This operation takes no arguments (an empty object).
Response:
On success, the result is a TestingGetFlightRecordsResponse object.
interface TestingGetFlightRecordsResponse {
flightRecords: FlightRecordEntry[];
}
interface FlightRecordEntry {
timestamp: TalerPreciseTimestamp;
target: string;
event: FlightRecordEvent;
}
type FlightRecordEvent = "melt-gone" | "withdrawal-redenominate";
- testingGetPerformanceStatsread-only#
Get a list of performance stats for diagnostics. Requires observability events to be enabled; performance tables for the current running wallet instance are generated from observability events and stored in memory. Under each table, different types of duration for each operation (e.g. a
getBalanceswallet request) are included.Request:
The request must be a GetPerformanceStatsRequest object.
Response:
On success, the result is a GetPerformanceStatsResponse object.
interface GetPerformanceStatsRequest {
// Limit to N largest average performance stats of each table.
// When undefined, all performance stats will be returned.
limit?: number;
}
interface GetPerformanceStatsResponse {
stats: PerformanceTable;
}
type PerformanceTable = {
[key in PerformanceStatType]?: PerformanceStat[];
};
type PerformanceStatType =
| "http-fetch"
| "db-query"
| "crypto"
| "wallet-request"
| "wallet-task";
type PerformanceStat =
| {
type: "http-fetch";
url: string;
avgDurationMs: number;
maxDurationMs: number;
minDurationMs: number;
totalDurationMs: number;
count: number;
}
| {
type: "db-query";
name: string;
location: string;
avgDurationMs: number;
maxDurationMs: number;
minDurationMs: number;
totalDurationMs: number;
count: number;
}
| {
type: "crypto";
operation: string;
avgDurationMs: number;
maxDurationMs: number;
minDurationMs: number;
totalDurationMs: number;
count: number;
}
| {
type: "wallet-request";
operation: string;
avgDurationMs: number;
maxDurationMs: number;
minDurationMs: number;
totalDurationMs: number;
count: number;
}
| {
type: "wallet-task";
taskId: string;
avgDurationMs: number;
maxDurationMs: number;
minDurationMs: number;
totalDurationMs: number;
count: number;
};
- testingCorruptWithdrawalCoinSel#
Corrupt the denomination selection of a withdrawal transaction by replacing the first selected denomination’s public key hash with a random value, in order to test the wallet’s error handling.
Request:
The request must be a TestingCorruptWithdrawalCoinSelRequest object.
Response:
On success, the result is an empty object.
Side effects:
Intentionally corrupts the withdrawal’s coin selection in the wallet database (test failure injection).
Details:
The
transactionIdmust identify a withdrawal transaction. Withdrawal groups without a denomination selection are left unchanged.
interface TestingCorruptWithdrawalCoinSelRequest {
transactionId: TransactionIdStr;
}
20.5.5. Notifications#
Notifications are sent by wallet-core to all connected clients whenever
relevant state changes. The payload of a CoreApiNotification is a
WalletNotification, a discriminated union on the type field. Clients
should treat notifications as hints to re-query the affected state; the
notification contents are deliberately minimal and must not be relied upon
as an authoritative state transfer.
type WalletNotification =
| CoinRecoveryProgressNotification
| BalanceChangeNotification
| BankAccountChangeNotification
| BackupOperationErrorNotification
| ContactAddedNotification
| ContactDeletedNotification
| MailboxMessageAddedNotification
| MailboxMessageDeletedNotification
| ExchangeStateTransitionNotification
| TransactionStateTransitionNotification
| TaskProgressNotification
| RequestObservabilityEventNotification
| IdleNotification
| RequestProgressNotification
| RequestProgressPhaseNotification
| DatabaseMaintenanceProgressNotification;
enum NotificationType {
CoinRecoveryProgress = "coin-recovery-progress",
BalanceChange = "balance-change",
BankAccountChange = "bank-account-change",
BackupOperationError = "backup-error",
ContactAdded = "contact-added",
ContactDeleted = "contact-deleted",
MailboxMessageAdded = "mailbox-message-added",
MailboxMessageDeleted = "mailbox-message-deleted",
TransactionStateTransition = "transaction-state-transition",
ExchangeStateTransition = "exchange-state-transition",
Idle = "idle",
TaskObservabilityEvent = "task-observability-event",
RequestObservabilityEvent = "request-observability-event",
RequestProgressError = "request-progress-error",
RequestProgressPhase = "request-progress-phase",
DatabaseMaintenanceProgress = "database-maintenance-progress",
}
coin-recovery-progress
Emitted while the testingRecoverCoins
operation scans an exchange for coins that belong to the wallet and recovers
them. The progressToken matches the progress token of the initiating
request.
The payload is a CoinRecoveryProgressNotification object.
interface CoinRecoveryProgressNotification {
type: NotificationType.CoinRecoveryProgress;
exchangeBaseUrl: string;
progressToken: string;
phase: CoinRecoveryPhase;
numChecked: number;
numDiscovered: number;
numQueued: number;
numRecovered: number;
recoveredAmount: AmountString;
numIssues: number;
}
type CoinRecoveryPhase =
| "starting"
| "history"
| "derive"
| "melt"
| "reveal"
| "refresh"
| "complete"
| "incomplete"
| "failed"
| "cancelled";
balance-change
Invalidates balance data, including flags and refresh information. The monetary amounts need not have changed, for example when a refresh cost becomes ready. Clients should re-query getBalances in response.
The payload is a BalanceChangeNotification object.
interface BalanceChangeNotification {
type: NotificationType.BalanceChange;
// If set to true, the balance change is internal to the wallet
// and not visible to the user. (For example when the material
// balance changes via a refresh, but the available balance
// stays the same.)
isInternal?: boolean;
// Transaction ID of the transaction that caused the balance
// update. Only used as a hint for debugging, should not be
// relied upon by clients.
hintTransactionId: string;
}
bank-account-change
Emitted when a bank account known to the wallet was added, changed or deleted. Clients should re-query listBankAccounts.
The payload is a BankAccountChangeNotification object.
interface BankAccountChangeNotification {
type: NotificationType.BankAccountChange;
// ID of the affected bank account.
bankAccountId: string;
}
backup-error
Signals the failure of a backup operation. The current wallet-core implementation does not emit this notification.
The payload is a BackupOperationErrorNotification object.
interface BackupOperationErrorNotification {
type: NotificationType.BackupOperationError;
error: TalerErrorDetail;
}
contact-added
Emitted when a contact was added to the wallet’s address book. Clients should re-query getContacts.
The payload is a ContactAddedNotification object.
interface ContactAddedNotification {
type: NotificationType.ContactAdded;
// The contact that was added.
contact: ContactEntry;
}
contact-deleted
Emitted when a contact was deleted from the wallet’s address book. Clients should re-query getContacts.
The payload is a ContactDeletedNotification object.
interface ContactDeletedNotification {
type: NotificationType.ContactDeleted;
// The contact that was deleted.
contact: ContactEntry;
}
mailbox-message-added
Emitted when a message was added to the wallet’s mailbox, for example a payment request received from another wallet user.
The payload is a MailboxMessageAddedNotification object.
interface MailboxMessageAddedNotification {
type: NotificationType.MailboxMessageAdded;
// The message that was added.
message: MailboxMessageRecord;
}
mailbox-message-deleted
Emitted when a message was deleted from the wallet’s mailbox.
The payload is a MailboxMessageDeletedNotification object.
interface MailboxMessageDeletedNotification {
type: NotificationType.MailboxMessageDeleted;
// The message that was deleted.
message: MailboxMessageRecord;
}
transaction-state-transition
Emitted when a transaction moves from one state to another. Clients should
re-query the affected transaction; the causeHint is only a debugging
aid and must not be relied upon.
The payload is a TransactionStateTransitionNotification object.
interface TransactionStateTransitionNotification {
type: NotificationType.TransactionStateTransition;
// Identifier of the affected transaction.
transactionId: string;
// A hint as to why the transition happened.
// Should not be relied upon by clients.
causeHint: string | undefined;
// State before the transition.
oldTxState: TransactionState;
// State after the transition.
newTxState: TransactionState;
// Internal ID of the new state. Must not be used by the UI,
// only used for testing.
newStId: number;
// Short summary of the error for an error transition.
errorInfo?: ErrorInfoSummary;
}
interface ErrorInfoSummary {
code: number;
hint?: string;
message?: string;
}
exchange-state-transition
Emitted when the state of an exchange entry changes. If
oldExchangeState is missing, the entry was newly created; if
newExchangeState is missing, the entry was deleted.
The payload is an ExchangeStateTransitionNotification object.
interface ExchangeStateTransitionNotification {
type: NotificationType.ExchangeStateTransition;
// Identification of the exchange entry that this
// notification is about.
exchangeBaseUrl: string;
// A hint as to why the transition happened.
// Should not be relied upon by clients.
causeHint: string | undefined;
// If missing, the notification means that
// the exchange entry is newly created.
oldExchangeState?: ExchangeEntryState;
// New state of the exchange.
// If missing, the exchange entry got deleted.
newExchangeState?: ExchangeEntryState;
// Summary of the error that occurred when trying to update
// the exchange entry, if applicable.
errorInfo?: ErrorInfoSummary;
}
interface ExchangeEntryState {
// Status of the exchange's terms of service.
tosStatus: ExchangeTosStatus;
// Lifecycle status of the exchange entry.
exchangeEntryStatus: ExchangeEntryStatus;
// Status of the last update of the exchange's key material.
exchangeUpdateStatus: ExchangeUpdateStatus;
}
idle
Emitted when wallet-core becomes idle, that is when no background task that keeps the wallet active is running anymore. Mainly useful for test harnesses that wait for the wallet to quiesce.
The payload is an IdleNotification object.
interface IdleNotification {
type: NotificationType.Idle;
}
task-observability-event
Reports a single observability event of a background task. These
notifications are only emitted when the testing option
emitObservabilityEvents is enabled in the wallet run configuration.
The payload is a TaskProgressNotification object.
interface TaskProgressNotification {
type: NotificationType.TaskObservabilityEvent;
taskId: string;
event: ObservabilityEvent;
}
type ObservabilityEvent =
| {
id: string;
when: AbsoluteTime;
type: ObservabilityEventType.HttpFetchStart;
url: string;
longPolling: boolean;
}
| {
id: string;
when: AbsoluteTime;
type: ObservabilityEventType.HttpFetchFinishSuccess;
url: string;
status: number;
durationMs: number;
longPolling: boolean;
}
| {
id: string;
when: AbsoluteTime;
type: ObservabilityEventType.HttpFetchFinishError;
url: string;
error: TalerErrorDetail;
durationMs: number;
longPolling: boolean;
}
| {
type: ObservabilityEventType.DbQueryStart;
name: string;
location: string;
}
| {
type: ObservabilityEventType.DbQueryFinishSuccess;
name: string;
location: string;
durationMs: number;
}
| {
type: ObservabilityEventType.DbQueryFinishError;
name: string;
location: string;
error: TalerErrorDetail;
durationMs: number;
}
| {
type: ObservabilityEventType.RequestStart;
name: string;
}
| {
type: ObservabilityEventType.RequestFinishSuccess;
operation: string;
requestId: string;
durationMs: number;
}
| {
type: ObservabilityEventType.RequestFinishError;
operation: string;
requestId: string;
durationMs: number;
}
| {
type: ObservabilityEventType.TaskStart;
taskId: string;
}
| {
type: ObservabilityEventType.TaskStop;
taskId: string;
}
| {
type: ObservabilityEventType.TaskReset;
taskId: string;
}
| {
type: ObservabilityEventType.DeclareTaskDependency;
taskId: string;
}
| {
type: ObservabilityEventType.CryptoStart;
operation: string;
}
| {
type: ObservabilityEventType.CryptoFinishSuccess;
operation: string;
durationMs: number;
}
| {
type: ObservabilityEventType.CryptoFinishError;
operation: string;
durationMs: number;
}
| {
type: ObservabilityEventType.ShepherdTaskResult;
taskId: string;
resultType: string;
durationMs: number;
}
| {
type: ObservabilityEventType.Message;
contents: string;
}
| {
type: ObservabilityEventType.DeclareConcernsTransaction;
transactionId: TransactionIdStr;
};
enum ObservabilityEventType {
HttpFetchStart = "http-fetch-start",
HttpFetchFinishError = "http-fetch-finish-error",
HttpFetchFinishSuccess = "http-fetch-finish-success",
DbQueryStart = "db-query-start",
DbQueryFinishSuccess = "db-query-finish-success",
DbQueryFinishError = "db-query-finish-error",
RequestStart = "request-start",
RequestFinishSuccess = "request-finish-success",
RequestFinishError = "request-finish-error",
TaskStart = "task-start",
TaskStop = "task-stop",
TaskReset = "task-reset",
ShepherdTaskResult = "shepherd-task-result",
DeclareTaskDependency = "declare-task-dependency",
CryptoStart = "crypto-start",
CryptoFinishSuccess = "crypto-finish-success",
CryptoFinishError = "crypto-finish-error",
Message = "message",
// Declares that an observability event is relevant to a particular
// transaction. If emitted from a request/task, all past/future
// events for that request/task should be shown for the
// transaction as well.
DeclareConcernsTransaction = "declare-concerns-transaction",
}
request-observability-event
Reports a single observability event of an API request; requestId
matches the id of the corresponding request envelope. These
notifications are only emitted when the testing option
emitObservabilityEvents is enabled in the wallet run configuration.
The payload is a RequestObservabilityEventNotification object.
interface RequestObservabilityEventNotification {
type: NotificationType.RequestObservabilityEvent;
requestId: string;
operation: string;
event: ObservabilityEvent;
}
request-progress-error
Emitted when an attempt of a long-running request with a progressToken
failed and will be retried automatically after nextRetryDelay. The
client can cancel the request with
cancelProgressToken or trigger an
immediate retry with
retryProgressTokenNow.
The payload is a RequestProgressNotification object.
interface RequestProgressNotification {
type: NotificationType.RequestProgressError;
progressToken: string;
operation: string;
error: TalerErrorDetail;
nextRetryDelay: TalerProtocolDuration;
retryCounter: number;
}
request-progress-phase
Emitted when a long-running request with a progressToken takes longer
than expected: delayed after about five seconds, stalled after
about ten seconds (at which point the user may want to retry), and
done when the request finished and no further progress notifications
will be sent.
The payload is a RequestProgressPhaseNotification object.
interface RequestProgressPhaseNotification {
type: NotificationType.RequestProgressPhase;
progressToken: string;
operation: string;
// delayed: request is taking longer than expected (usually
// after 5s)
// stalled: request is taking *very* long, user can retry
// (usually after 10s)
// done: no further progress notifications will be sent
phase: "delayed" | "stalled" | "done";
}
database-maintenance-progress
Emitted while startup fixups or a database migration hold the database
gate, reporting progress of the maintenance operation. Intermediate
updates may be coalesced by wallet-core, but the first and the terminal
(complete or failed) events are always delivered.
The payload is a DatabaseMaintenanceProgressNotification object.
interface DatabaseMaintenanceProgressNotification {
type: NotificationType.DatabaseMaintenanceProgress;
operation:
| "indexeddb-fixup"
| "indexeddb-to-native-migration"
| "cross-backend-import";
// Token of the API request that initiated this operation,
// when available.
progressToken?: string;
phase: "fixup" | "copy" | "verify" | "complete" | "failed";
// Current fixup or backend-neutral store, when one is active.
step?: string;
completedSteps: number;
totalSteps: number;
// Records completed in the current phase across the
// whole migration.
processedRecords?: number;
// Total records in the whole migration, known before
// copying starts.
totalRecords?: number;
// Rough overall migration completion, from 0 through 100.
completionPercent?: number;
// Why the maintenance operation failed. Present when
// phase is "failed".
error?: TalerErrorDetail;
}