import { codecForAmountString } from "../amounts.js"; import { Codec, buildCodecForObject, buildCodecForUnion, codecForAny, codecForBoolean, codecForConstString, codecForEither, codecForList, codecForMap, codecForNumber, codecForString, codecOptional, } from "../codec.js"; import { PaytoString, codecForPaytoString } from "../payto.js"; import { AmountString } from "../taler-types.js"; import { TalerActionString, codecForTalerActionString } from "../taleruri.js"; import { codecForTimestamp } from "../time.js"; export type UserAndPassword = { username: string; password: string; }; export type UserAndToken = { username: string; token: AccessToken; }; declare const opaque_OfficerAccount: unique symbol; export type LockedAccount = string & { [opaque_OfficerAccount]: true }; declare const opaque_OfficerId: unique symbol; export type OfficerId = string & { [opaque_OfficerId]: true }; declare const opaque_OfficerSigningKey: unique symbol; export type SigningKey = Uint8Array & { [opaque_OfficerSigningKey]: true }; export interface OfficerAccount { id: OfficerId; signingKey: SigningKey; } export type PaginationParams = { /** * row identifier as the starting point of the query */ offset?: string; /** * max number of element in the result response * always greater than 0 */ limit?: number; /** * milliseconds the server should wait for at least one result to be shown */ timoutMs?: number; /** * order */ order: "asc" | "dec"; }; /// /// HASH /// // 64-byte hash code. type HashCode = string; type PaytoHash = string; type AmlOfficerPublicKeyP = string; // 32-byte hash code. type ShortHashCode = string; // 16-byte salt. type WireSalt = string; type SHA256HashCode = ShortHashCode; type SHA512HashCode = HashCode; // 32-byte nonce value, must only be used once. type CSNonce = string; // 32-byte nonce value, must only be used once. type RefreshMasterSeed = string; // 32-byte value representing a point on Curve25519. type Cs25519Point = string; // 32-byte value representing a scalar multiplier // for scalar operations on points on Curve25519. type Cs25519Scalar = string; /// /// KEYS /// // 16-byte access token used to authorize access. type ClaimToken = string; // EdDSA and ECDHE public keys always point on Curve25519 // and represented using the standard 256 bits Ed25519 compact format, // converted to Crockford Base32. type EddsaPublicKey = string; // EdDSA and ECDHE public keys always point on Curve25519 // and represented using the standard 256 bits Ed25519 compact format, // converted to Crockford Base32. type EddsaPrivateKey = string; // Edx25519 public keys are points on Curve25519 and represented using the // standard 256 bits Ed25519 compact format converted to Crockford // Base32. type Edx25519PublicKey = string; // Edx25519 private keys are always points on Curve25519 // and represented using the standard 256 bits Ed25519 compact format, // converted to Crockford Base32. type Edx25519PrivateKey = string; // EdDSA and ECDHE public keys always point on Curve25519 // and represented using the standard 256 bits Ed25519 compact format, // converted to Crockford Base32. type EcdhePublicKey = string; // Point on Curve25519 represented using the standard 256 bits Ed25519 compact format, // converted to Crockford Base32. type CsRPublic = string; // EdDSA and ECDHE public keys always point on Curve25519 // and represented using the standard 256 bits Ed25519 compact format, // converted to Crockford Base32. type EcdhePrivateKey = string; type CoinPublicKey = EddsaPublicKey; // RSA public key converted to Crockford Base32. type RsaPublicKey = string; type Integer = number; type WireTransferIdentifierRawP = string; // Subset of numbers: Integers in the // inclusive range 0 .. (2^53 - 1). type SafeUint64 = number; // The string must be a data URL according to RFC 2397 // with explicit mediatype and base64 parameters. // // data:;base64, // // Supported mediatypes are image/jpeg and image/png. // Invalid strings will be rejected by the wallet. type ImageDataUrl = string; type WadId = string; interface Timestamp { // Seconds since epoch, or the special // value "never" to represent an event that will // never happen. t_s: number | "never"; } interface RelativeTime { // Duration in microseconds or "forever" // to represent an infinite duration. Numeric // values are capped at 2^53 - 1 inclusive. d_us: number | "forever"; } export interface LoginToken { token: AccessToken; expiration: Timestamp; } declare const __ac_token: unique symbol; export type AccessToken = string & { [__ac_token]: true; }; declare const __officer_signature: unique symbol; export type OfficerSignature = string & { [__officer_signature]: true; }; export namespace TalerAuthentication { export interface TokenRequest { // Service-defined scope for the token. // Typical scopes would be "readonly" or "readwrite". scope: string; // Server may impose its own upper bound // on the token validity duration duration?: RelativeTime; // Is the token refreshable into a new token during its // validity? // Refreshable tokens effectively provide indefinite // access if they are refreshed in time. refreshable?: boolean; } export interface TokenSuccessResponse { // Expiration determined by the server. // Can be based on the token_duration // from the request, but ultimately the // server decides the expiration. expiration: Timestamp; // Opque access token. access_token: AccessToken; } } // DD51 https://docs.taler.net/design-documents/051-fractional-digits.html export 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, if needed by // padding with zeros. num_fractional_trailing_zero_digits: Integer; // map of powers of 10 to alternative currency names / symbols, must // always have an entry under "0" that defines the base name, // e.g. "0 => €" or "3 => k€". For BTC, would be "0 => BTC, -3 => mBTC". // Communicates the currency symbol to be used. alt_unit_names: { [log10: string]: string }; } export const codecForAccessToken = codecForString as () => Codec; export const codecForTokenSuccessResponse = (): Codec => buildCodecForObject() .property("access_token", codecForAccessToken()) .property("expiration", codecForTimestamp) .build("TalerAuthentication.TokenSuccessResponse"); export const codecForCurrencySpecificiation = (): Codec => buildCodecForObject() .property("name", codecForString()) .property("num_fractional_input_digits", codecForNumber()) .property("num_fractional_normal_digits", codecForNumber()) .property("num_fractional_trailing_zero_digits", codecForNumber()) .property("alt_unit_names", codecForMap(codecForString())) .build("CurrencySpecification"); export const codecForIntegrationBankConfig = (): Codec => buildCodecForObject() .property("name", codecForConstString("taler-bank-integration")) .property("version", codecForString()) .property("currency", codecForString()) .property("currency_specification", codecForCurrencySpecificiation()) .build("TalerCorebankApi.IntegrationConfig"); export const codecForCoreBankConfig = (): Codec => buildCodecForObject() .property("name", codecForConstString("libeufin-bank")) .property("version", codecForString()) .property("allow_conversion", codecForBoolean()) .property("allow_deletions", codecForBoolean()) .property("allow_registrations", codecForBoolean()) .property("default_debit_threshold", codecForAmountString()) .property("currency_specification", codecForCurrencySpecificiation()) .property("currency", codecForString()) .build("TalerCorebankApi.Config"); export const codecForMerchantConfig = (): Codec => buildCodecForObject() .property("name", codecForConstString("taler-merchant")) .property("currency", codecForString()) .property("version", codecForString()) .property("currencies", codecForMap(codecForCurrencySpecificiation())) .build("TalerMerchantApi.VersionResponse"); export const codecForExchangeConfig = (): Codec => buildCodecForObject() .property("version", codecForString()) .property("name", codecForConstString("taler-exchange")) .property("currency", codecForString()) .property("currency_specification", codecForCurrencySpecificiation()) .property("supported_kyc_requirements", codecForList(codecForString())) .build("TalerExchangeApi.ExchangeVersionResponse"); const codecForBalance = (): Codec => buildCodecForObject() .property("amount", codecForAmountString()) .property( "credit_debit_indicator", codecForEither( codecForConstString("credit"), codecForConstString("debit"), ), ) .build("TalerCorebankApi.Balance"); const codecForPublicAccount = (): Codec => buildCodecForObject() .property("account_name", codecForString()) .property("balance", codecForBalance()) .property("payto_uri", codecForPaytoString()) .build("TalerCorebankApi.PublicAccount"); export const codecForPublicAccountsResponse = (): Codec => buildCodecForObject() .property("public_accounts", codecForList(codecForPublicAccount())) .build("TalerCorebankApi.PublicAccountsResponse"); export const codecForAccountMinimalData = (): Codec => buildCodecForObject() .property("balance", codecForBalance()) .property("debit_threshold", codecForAmountString()) .property("name", codecForString()) .property("username", codecForString()) .build("TalerCorebankApi.AccountMinimalData"); export const codecForListBankAccountsResponse = (): Codec => buildCodecForObject() .property("accounts", codecForList(codecForAccountMinimalData())) .build("TalerCorebankApi.ListBankAccountsResponse"); export const codecForAccountData = (): Codec => buildCodecForObject() .property("name", codecForString()) .property("balance", codecForBalance()) .property("payto_uri", codecForPaytoString()) .property("debit_threshold", codecForAmountString()) .property("contact_data", codecOptional(codecForChallengeContactData())) .property("cashout_payto_uri", codecOptional(codecForPaytoString())) .build("TalerCorebankApi.AccountData"); export const codecForChallengeContactData = (): Codec => buildCodecForObject() .property("email", codecOptional(codecForString())) .property("phone", codecOptional(codecForString())) .build("TalerCorebankApi.ChallengeContactData"); export const codecForWithdrawalPublicInfo = (): Codec => buildCodecForObject() .property("username", codecForString()) .property("amount", codecForAmountString()) .property( "selected_exchange_account", codecOptional(codecForPaytoString()), ) .property("selected_reserve_pub", codecOptional(codecForString())) .property( "status", codecForEither( codecForConstString("pending"), codecForConstString("selected"), codecForConstString("aborted"), codecForConstString("confirmed"), ), ) .build("TalerCorebankApi.WithdrawalPublicInfo"); export const codecForBankAccountTransactionsResponse = (): Codec => buildCodecForObject() .property( "transactions", codecForList(codecForBankAccountTransactionInfo()), ) .build("TalerCorebankApi.BankAccountTransactionsResponse"); export const codecForBankAccountTransactionInfo = (): Codec => buildCodecForObject() .property("creditor_payto_uri", codecForPaytoString()) .property("debtor_payto_uri", codecForPaytoString()) .property("amount", codecForAmountString()) .property( "direction", codecForEither( codecForConstString("debit"), codecForConstString("credit"), ), ) .property("subject", codecForString()) .property("row_id", codecForNumber()) .property("date", codecForTimestamp) .build("TalerCorebankApi.BankAccountTransactionInfo"); export const codecForCreateTransactionResponse = (): Codec => buildCodecForObject() .property("row_id", codecForNumber()) .build("TalerCorebankApi.CreateTransactionResponse"); export const codecForRegisterAccountResponse = (): Codec => buildCodecForObject() .property("internal_payto_uri", codecForPaytoString()) .build("TalerCorebankApi.RegisterAccountResponse"); export const codecForBankAccountCreateWithdrawalResponse = (): Codec => buildCodecForObject() .property("taler_withdraw_uri", codecForTalerActionString()) .property("withdrawal_id", codecForString()) .build("TalerCorebankApi.BankAccountCreateWithdrawalResponse"); export const codecForCashoutPending = (): Codec => buildCodecForObject() .property("cashout_id", codecForNumber()) .build("TalerCorebankApi.CashoutPending"); export const codecForCashoutConversionResponse = (): Codec => buildCodecForObject() .property("amount_credit", codecForAmountString()) .property("amount_debit", codecForAmountString()) .build("TalerCorebankApi.CashoutConversionResponse"); export const codecForCashinConversionResponse = (): Codec => buildCodecForObject() .property("amount_credit", codecForAmountString()) .property("amount_debit", codecForAmountString()) .build("TalerCorebankApi.CashinConversionResponse"); export const codecForCashouts = (): Codec => buildCodecForObject() .property("cashouts", codecForList(codecForCashoutInfo())) .build("TalerCorebankApi.Cashouts"); export const codecForCashoutInfo = (): Codec => buildCodecForObject() .property("cashout_id", codecForNumber()) .property( "status", codecForEither( codecForConstString("pending"), codecForConstString("aborted"), codecForConstString("confirmed"), ), ) .build("TalerCorebankApi.CashoutInfo"); export const codecForGlobalCashouts = (): Codec => buildCodecForObject() .property("cashouts", codecForList(codecForGlobalCashoutInfo())) .build("TalerCorebankApi.GlobalCashouts"); export const codecForGlobalCashoutInfo = (): Codec => buildCodecForObject() .property("cashout_id", codecForNumber()) .property("username", codecForString()) .property( "status", codecForEither( codecForConstString("pending"), codecForConstString("aborted"), codecForConstString("confirmed"), ), ) .build("TalerCorebankApi.GlobalCashoutInfo"); export const codecForCashoutStatusResponse = (): Codec => buildCodecForObject() .property("amount_credit", codecForAmountString()) .property("amount_debit", codecForAmountString()) .property("confirmation_time", codecOptional(codecForTimestamp)) .property("creation_time", codecForTimestamp) // .property("credit_payto_uri", codecForPaytoString()) .property( "status", codecForEither( codecForConstString("pending"), codecForConstString("aborted"), codecForConstString("confirmed"), ), ) .property( "tan_channel", codecForEither( codecForConstString(TanChannel.SMS), codecForConstString(TanChannel.EMAIL), ), ) .property("subject", codecForString()) .property("tan_info", codecForString()) .build("TalerCorebankApi.CashoutStatusResponse"); export const codecForConversionRatesResponse = (): Codec => buildCodecForObject() .property("buy_at_ratio", codecForDecimalNumber()) .property("buy_in_fee", codecForDecimalNumber()) .property("sell_at_ratio", codecForDecimalNumber()) .property("sell_out_fee", codecForDecimalNumber()) .build("TalerCorebankApi.ConversionRatesResponse"); export const codecForMonitorResponse = (): Codec => buildCodecForUnion() .discriminateOn("type") .alternative("no-conversions", codecForMonitorNoConversion()) .alternative("with-conversions", codecForMonitorWithCashout()) .build("TalerWireGatewayApi.IncomingBankTransaction"); export const codecForMonitorNoConversion = (): Codec => buildCodecForObject() .property("type", codecForConstString("no-conversions")) .property("talerInCount", codecForNumber()) .property("talerInVolume", codecForAmountString()) .property("talerOutCount", codecForNumber()) .property("talerOutVolume", codecForAmountString()) .build("TalerCorebankApi.MonitorJustPayouts"); export const codecForMonitorWithCashout = (): Codec => buildCodecForObject() .property("type", codecForConstString("with-conversions")) .property("cashinCount", codecForNumber()) .property("cashinFiatVolume", codecForAmountString()) .property("cashinRegionalVolume", codecForAmountString()) .property("cashoutCount", codecForNumber()) .property("cashoutFiatVolume", codecForAmountString()) .property("cashoutRegionalVolume", codecForAmountString()) .property("talerInCount", codecForNumber()) .property("talerInVolume", codecForAmountString()) .property("talerOutCount", codecForNumber()) .property("talerOutVolume", codecForAmountString()) .build("TalerCorebankApi.MonitorWithCashout"); export const codecForBankVersion = (): Codec => buildCodecForObject() .property("currency", codecForCurrencyName()) .property("currency_specification", codecForCurrencySpecificiation()) .property("name", codecForConstString("taler-bank-integration")) .property("version", codecForLibtoolVersion()) .build("TalerBankIntegrationApi.BankVersion"); export const codecForBankWithdrawalOperationStatus = (): Codec => buildCodecForObject() .property( "status", codecForEither( codecForConstString("pending"), codecForConstString("selected"), codecForConstString("aborted"), codecForConstString("confirmed"), ), ) .property("amount", codecForAmountString()) .property("sender_wire", codecOptional(codecForPaytoString())) .property("suggested_exchange", codecOptional(codecForString())) .property("confirm_transfer_url", codecOptional(codecForURL())) .property("wire_types", codecForList(codecForString())) .property("selected_reserve_pub", codecOptional(codecForString())) .property("selected_exchange_account", codecOptional(codecForString())) .build("TalerBankIntegrationApi.BankWithdrawalOperationStatus"); export const codecForBankWithdrawalOperationPostResponse = (): Codec => buildCodecForObject() .property( "status", codecForEither( codecForConstString("pending"), codecForConstString("selected"), codecForConstString("aborted"), codecForConstString("confirmed"), ), ) .property("confirm_transfer_url", codecOptional(codecForURL())) .build("TalerBankIntegrationApi.BankWithdrawalOperationPostResponse"); export const codecForMerchantIncomingHistory = (): Codec => buildCodecForObject() .property("credit_account", codecForPaytoString()) .property( "incoming_transactions", codecForList(codecForMerchantIncomingBankTransaction()), ) .build("TalerRevenueApi.MerchantIncomingHistory"); export const codecForMerchantIncomingBankTransaction = (): Codec => buildCodecForObject() .property("row_id", codecForNumber()) .property("date", codecForTimestamp) .property("amount", codecForAmountString()) .property("debit_account", codecForPaytoString()) .property("exchange_url", codecForURL()) .property("wtid", codecForString()) .build("TalerRevenueApi.MerchantIncomingBankTransaction"); export const codecForTransferResponse = (): Codec => buildCodecForObject() .property("row_id", codecForNumber()) .property("timestamp", codecForTimestamp) .build("TalerWireGatewayApi.TransferResponse"); export const codecForIncomingHistory = (): Codec => buildCodecForObject() .property("credit_account", codecForPaytoString()) .property( "incoming_transactions", codecForList(codecForIncomingBankTransaction()), ) .build("TalerWireGatewayApi.IncomingHistory"); export const codecForIncomingBankTransaction = (): Codec => buildCodecForUnion() .discriminateOn("type") .alternative("RESERVE", codecForIncomingReserveTransaction()) .alternative("WAD", codecForIncomingWadTransaction()) .build("TalerWireGatewayApi.IncomingBankTransaction"); export const codecForIncomingReserveTransaction = (): Codec => buildCodecForObject() .property("amount", codecForAmountString()) .property("date", codecForTimestamp) .property("debit_account", codecForPaytoString()) .property("reserve_pub", codecForString()) .property("row_id", codecForNumber()) .property("type", codecForConstString("RESERVE")) .build("TalerWireGatewayApi.IncomingReserveTransaction"); export const codecForIncomingWadTransaction = (): Codec => buildCodecForObject() .property("amount", codecForAmountString()) .property("credit_account", codecForPaytoString()) .property("date", codecForTimestamp) .property("debit_account", codecForPaytoString()) .property("origin_exchange_url", codecForURL()) .property("row_id", codecForNumber()) .property("type", codecForConstString("WAD")) .property("wad_id", codecForString()) .build("TalerWireGatewayApi.IncomingWadTransaction"); export const codecForOutgoingHistory = (): Codec => buildCodecForObject() .property("debit_account", codecForPaytoString()) .property( "outgoing_transactions", codecForList(codecForOutgoingBankTransaction()), ) .build("TalerWireGatewayApi.OutgoingHistory"); export const codecForOutgoingBankTransaction = (): Codec => buildCodecForObject() .property("amount", codecForAmountString()) .property("credit_account", codecForPaytoString()) .property("date", codecForTimestamp) .property("exchange_base_url", codecForURL()) .property("row_id", codecForNumber()) .property("wtid", codecForString()) .build("TalerWireGatewayApi.OutgoingBankTransaction"); export const codecForAddIncomingResponse = (): Codec => buildCodecForObject() .property("row_id", codecForNumber()) .property("timestamp", codecForTimestamp) .build("TalerWireGatewayApi.AddIncomingResponse"); export const codecForAmlRecords = (): Codec => buildCodecForObject() .property("records", codecForList(codecForAmlRecord())) .build("TalerExchangeApi.PublicAccountsResponse"); export const codecForAmlRecord = (): Codec => buildCodecForObject() .property("current_state", codecForNumber()) .property("h_payto", codecForString()) .property("rowid", codecForNumber()) .property("threshold", codecForAmountString()) .build("TalerExchangeApi.AmlRecord"); export const codecForAmlDecisionDetails = (): Codec => buildCodecForObject() .property("aml_history", codecForList(codecForAmlDecisionDetail())) .property("kyc_attributes", codecForList(codecForKycDetail())) .build("TalerExchangeApi.AmlDecisionDetails"); export const codecForAmlDecisionDetail = (): Codec => buildCodecForObject() .property("justification", codecForString()) .property("new_state", codecForNumber()) .property("decision_time", codecForTimestamp) .property("new_threshold", codecForAmountString()) .property("decider_pub", codecForString()) .build("TalerExchangeApi.AmlDecisionDetail"); interface KycDetail { provider_section: string; attributes?: Object; collection_time: Timestamp; expiration_time: Timestamp; } export const codecForKycDetail = (): Codec => buildCodecForObject() .property("provider_section", codecForString()) .property("attributes", codecOptional(codecForAny())) .property("collection_time", codecForTimestamp) .property("expiration_time", codecForTimestamp) .build("TalerExchangeApi.KycDetail"); export const codecForAmlDecision = (): Codec => buildCodecForObject() .property("justification", codecForString()) .property("new_threshold", codecForAmountString()) .property("h_payto", codecForString()) .property("new_state", codecForNumber()) .property("officer_sig", codecForString()) .property("decision_time", codecForTimestamp) .property("kyc_requirements", codecOptional(codecForList(codecForString()))) .build("TalerExchangeApi.AmlDecision"); // version: string; // // Name of the API. // name: "taler-conversion-info"; // // Currency used by this bank. // regional_currency: string; // // How the bank SPA should render this currency. // regional_currency_specification: CurrencySpecification; // // External currency used during conversion. // fiat_currency: string; // // How the bank SPA should render this currency. // fiat_currency_specification: CurrencySpecification; // Extra conversion rate information. // // Only present if server opts in to report the static conversion rate. // conversion_info?: { // // Fee to subtract after applying the cashin ratio. // cashin_fee: AmountString; // // Fee to subtract after applying the cashout ratio. // cashout_fee: AmountString; // // Minimum amount authorised for cashin, in fiat before conversion // cashin_min_amount: AmountString; // // Minimum amount authorised for cashout, in regional before conversion // cashout_min_amount: AmountString; // // Smallest possible regional amount, converted amount is rounded to this amount // cashin_tiny_amount: AmountString; // // Smallest possible fiat amount, converted amount is rounded to this amount // cashout_tiny_amount: AmountString; // // Rounding mode used during cashin conversion // cashin_rounding_mode: "zero" | "up" | "nearest"; // // Rounding mode used during cashout conversion // cashout_rounding_mode: "zero" | "up" | "nearest"; // } export const codecForConversionInfo = (): Codec => buildCodecForObject() .property("cashin_fee", codecForAmountString()) .property("cashin_min_amount", codecForAmountString()) .property("cashin_ratio", codecForDecimalNumber()) .property( "cashin_rounding_mode", codecForEither( codecForConstString("zero"), codecForConstString("up"), codecForConstString("nearest"), ), ) .property("cashin_tiny_amount", codecForAmountString()) .property("cashout_fee", codecForAmountString()) .property("cashout_min_amount", codecForAmountString()) .property("cashout_ratio", codecForDecimalNumber()) .property( "cashout_rounding_mode", codecForEither( codecForConstString("zero"), codecForConstString("up"), codecForConstString("nearest"), ), ) .property("cashout_tiny_amount", codecForAmountString()) .build("ConversionBankConfig.ConversionInfo"); export const codecForConversionBankConfig = (): Codec => buildCodecForObject() .property("name", codecForConstString("taler-conversion-info")) .property("version", codecForString()) .property("regional_currency", codecForString()) .property( "regional_currency_specification", codecForCurrencySpecificiation(), ) .property("fiat_currency", codecForString()) .property("fiat_currency_specification", codecForCurrencySpecificiation()) .property("conversion_rate", codecOptional(codecForConversionInfo())) .build("ConversionBankConfig.IntegrationConfig"); // export const codecFor = // (): Codec => // buildCodecForObject() // .property("", codecForString()) // .build("TalerWireGatewayApi.PublicAccountsResponse"); type EmailAddress = string; type PhoneNumber = string; type EddsaSignature = string; // base32 encoded RSA blinded signature. type BlindedRsaSignature = string; type Base32 = string; type DecimalNumber = string; type RsaSignature = string; // The type of a coin's blinded envelope depends on the cipher that is used // for signing with a denomination key. type CoinEnvelope = RSACoinEnvelope | CSCoinEnvelope; // For denomination signatures based on RSA, the planchet is just a blinded // coin's public EdDSA key. interface RSACoinEnvelope { cipher: "RSA" | "RSA+age_restricted"; rsa_blinded_planchet: string; // Crockford Base32 encoded } // For denomination signatures based on Blind Clause-Schnorr, the planchet // consists of the public nonce and two Curve25519 scalars which are two // blinded challenges in the Blinded Clause-Schnorr signature scheme. // See https://taler.net/papers/cs-thesis.pdf for details. interface CSCoinEnvelope { cipher: "CS" | "CS+age_restricted"; cs_nonce: string; // Crockford Base32 encoded cs_blinded_c0: string; // Crockford Base32 encoded cs_blinded_c1: string; // Crockford Base32 encoded } // Secret for blinding/unblinding. // An RSA blinding secret, which is basically // a 256-bit nonce, converted to Crockford Base32. type DenominationBlindingKeyP = string; const codecForURL = codecForString; const codecForLibtoolVersion = codecForString; const codecForCurrencyName = codecForString; const codecForDecimalNumber = codecForString; enum TanChannel { SMS = "sms", EMAIL = "email", } export type WithdrawalOperationStatus = | "pending" | "selected" | "aborted" | "confirmed"; export namespace TalerWireGatewayApi { export interface TransferResponse { // Timestamp that indicates when the wire transfer will be executed. // In cases where the wire transfer gateway is unable to know when // the wire transfer will be executed, the time at which the request // has been received and stored will be returned. // The purpose of this field is for debugging (humans trying to find // the transaction) as well as for taxation (determining which // time period a transaction belongs to). timestamp: Timestamp; // Opaque ID of the transaction that the bank has made. row_id: SafeUint64; } export interface TransferRequest { // Nonce to make the request idempotent. Requests with the same // transaction_uid that differ in any of the other fields // are rejected. request_uid: HashCode; // Amount to transfer. amount: AmountString; // Base URL of the exchange. Shall be included by the bank gateway // in the appropriate section of the wire transfer details. exchange_base_url: string; // Wire transfer identifier chosen by the exchange, // used by the merchant to identify the Taler order(s) // associated with this wire transfer. wtid: ShortHashCode; // The recipient's account identifier as a payto URI. credit_account: PaytoString; } export interface IncomingHistory { // Array of incoming transactions. incoming_transactions: IncomingBankTransaction[]; // Payto URI to identify the receiver of funds. // This must be one of the exchange's bank accounts. // Credit account is shared by all incoming transactions // as per the nature of the request. // undefined if incoming transaction is empty credit_account?: PaytoString; } // Union discriminated by the "type" field. export type IncomingBankTransaction = | IncomingReserveTransaction | IncomingWadTransaction; export interface IncomingReserveTransaction { type: "RESERVE"; // Opaque identifier of the returned record. row_id: SafeUint64; // Date of the transaction. date: Timestamp; // Amount transferred. amount: AmountString; // Payto URI to identify the sender of funds. debit_account: PaytoString; // The reserve public key extracted from the transaction details. reserve_pub: EddsaPublicKey; } export interface IncomingWadTransaction { type: "WAD"; // Opaque identifier of the returned record. row_id: SafeUint64; // Date of the transaction. date: Timestamp; // Amount transferred. amount: AmountString; // Payto URI to identify the receiver of funds. // This must be one of the exchange's bank accounts. credit_account: PaytoString; // Payto URI to identify the sender of funds. debit_account: PaytoString; // Base URL of the exchange that originated the wad. origin_exchange_url: string; // The reserve public key extracted from the transaction details. wad_id: WadId; } export interface OutgoingHistory { // Array of outgoing transactions. outgoing_transactions: OutgoingBankTransaction[]; // Payto URI to identify the sender of funds. // This must be one of the exchange's bank accounts. // Credit account is shared by all incoming transactions // as per the nature of the request. // undefined if outgoing transactions is empty debit_account?: PaytoString; } export interface OutgoingBankTransaction { // Opaque identifier of the returned record. row_id: SafeUint64; // Date of the transaction. date: Timestamp; // Amount transferred. amount: AmountString; // Payto URI to identify the receiver of funds. credit_account: PaytoString; // The wire transfer ID in the outgoing transaction. wtid: ShortHashCode; // Base URL of the exchange. exchange_base_url: string; } export interface AddIncomingRequest { // Amount to transfer. amount: AmountString; // Reserve public key that is included in the wire transfer details // to identify the reserve that is being topped up. reserve_pub: EddsaPublicKey; // Account (as payto URI) that makes the wire transfer to the exchange. // Usually this account must be created by the test harness before this API is // used. An exception is the "exchange-fakebank", where any debit account can be // specified, as it is automatically created. debit_account: PaytoString; } export interface AddIncomingResponse { // Timestamp that indicates when the wire transfer will be executed. // In cases where the wire transfer gateway is unable to know when // the wire transfer will be executed, the time at which the request // has been received and stored will be returned. // The purpose of this field is for debugging (humans trying to find // the transaction) as well as for taxation (determining which // time period a transaction belongs to). timestamp: Timestamp; // Opaque ID of the transaction that the bank has made. row_id: SafeUint64; } } export namespace TalerRevenueApi { export interface MerchantIncomingHistory { // Array of incoming transactions. incoming_transactions: MerchantIncomingBankTransaction[]; // Payto URI to identify the receiver of funds. // This must be one of the merchant's bank accounts. // Credit account is shared by all incoming transactions // as per the nature of the request. credit_account: PaytoString; } export interface MerchantIncomingBankTransaction { // Opaque identifier of the returned record. row_id: SafeUint64; // Date of the transaction. date: Timestamp; // Amount transferred. amount: AmountString; // Payto URI to identify the sender of funds. debit_account: PaytoString; // Base URL of the exchange where the transfer originated form. exchange_url: string; // The wire transfer identifier. wtid: WireTransferIdentifierRawP; } } export namespace TalerBankConversionApi { export interface ConversionInfo { // Exchange rate to buy regional currency from fiat cashin_ratio: DecimalNumber; // Exchange rate to sell regional currency for fiat cashout_ratio: DecimalNumber; // Fee to subtract after applying the cashin ratio. cashin_fee: AmountString; // Fee to subtract after applying the cashout ratio. cashout_fee: AmountString; // Minimum amount authorised for cashin, in fiat before conversion cashin_min_amount: AmountString; // Minimum amount authorised for cashout, in regional before conversion cashout_min_amount: AmountString; // Smallest possible regional amount, converted amount is rounded to this amount cashin_tiny_amount: AmountString; // Smallest possible fiat amount, converted amount is rounded to this amount cashout_tiny_amount: AmountString; // Rounding mode used during cashin conversion cashin_rounding_mode: "zero" | "up" | "nearest"; // Rounding mode used during cashout conversion cashout_rounding_mode: "zero" | "up" | "nearest"; } export interface IntegrationConfig { // libtool-style representation of the Bank protocol version, see // https://www.gnu.org/software/libtool/manual/html_node/Versioning.html#Versioning // The format is "current:revision:age". version: string; // Name of the API. name: "taler-conversion-info"; // Currency used by this bank. regional_currency: string; // How the bank SPA should render this currency. regional_currency_specification: CurrencySpecification; // External currency used during conversion. fiat_currency: string; // How the bank SPA should render this currency. fiat_currency_specification: CurrencySpecification; // Extra conversion rate information. // Only present if server opts in to report the static conversion rate. conversion_rate?: ConversionInfo; } export interface CashinConversionResponse { // Amount that the user will get deducted from their fiat // bank account, according to the 'amount_credit' value. amount_debit: AmountString; // Amount that the user will receive in their regional // bank account, according to 'amount_debit'. amount_credit: AmountString; } export interface CashoutConversionResponse { // Amount that the user will get deducted from their regional // bank account, according to the 'amount_credit' value. amount_debit: AmountString; // Amount that the user will receive in their fiat // bank account, according to 'amount_debit'. amount_credit: AmountString; } export type RoundingMode = "zero" | "up" | "nearest"; export interface ConversionRate { // Exchange rate to buy regional currency from fiat cashin_ratio: DecimalNumber; // Fee to subtract after applying the cashin ratio. cashin_fee: AmountString; // Minimum amount authorised for cashin, in fiat before conversion cashin_min_amount: AmountString; // Smallest possible regional amount, converted amount is rounded to this amount cashin_tiny_amount: AmountString; // Rounding mode used during cashin conversion cashin_rounding_mode: RoundingMode; // Exchange rate to sell regional currency for fiat cashout_ratio: DecimalNumber; // Fee to subtract after applying the cashout ratio. cashout_fee: AmountString; // Minimum amount authorised for cashout, in regional before conversion cashout_min_amount: AmountString; // Smallest possible fiat amount, converted amount is rounded to this amount cashout_tiny_amount: AmountString; // Rounding mode used during cashout conversion cashout_rounding_mode: RoundingMode; } } export namespace TalerBankIntegrationApi { export interface BankVersion { // libtool-style representation of the Bank protocol version, see // https://www.gnu.org/software/libtool/manual/html_node/Versioning.html#Versioning // The format is "current:revision:age". version: string; // Currency used by this bank. currency: string; // How the bank SPA should render this currency. currency_specification?: CurrencySpecification; // Name of the API. name: "taler-bank-integration"; } export interface BankWithdrawalOperationStatus { // Current status of the operation // pending: the operation is pending parameters selection (exchange and reserve public key) // selected: the operations has been selected and is pending confirmation // aborted: the operation has been aborted // confirmed: the transfer has been confirmed and registered by the bank status: WithdrawalOperationStatus; // Amount that will be withdrawn with this operation // (raw amount without fee considerations). amount: AmountString; // Bank account of the customer that is withdrawing, as a // payto URI. sender_wire?: PaytoString; // Suggestion for an exchange given by the bank. suggested_exchange?: string; // URL that the user needs to navigate to in order to // complete some final confirmation (e.g. 2FA). // It may contain withdrawal operation id confirm_transfer_url?: string; // Wire transfer types supported by the bank. wire_types: string[]; // Reserve public key selected by the exchange, // only non-null if status is selected or confirmed. selected_reserve_pub?: string; // Exchange account selected by the wallet // only non-null if status is selected or confirmed. selected_exchange_account?: string; } export interface BankWithdrawalOperationPostRequest { // Reserve public key. reserve_pub: string; // Payto address of the exchange selected for the withdrawal. selected_exchange: PaytoString; } export interface BankWithdrawalOperationPostResponse { // Current status of the operation // pending: the operation is pending parameters selection (exchange and reserve public key) // selected: the operations has been selected and is pending confirmation // aborted: the operation has been aborted // confirmed: the transfer has been confirmed and registered by the bank status: Omit<"pending", WithdrawalOperationStatus>; // URL that the user needs to navigate to in order to // complete some final confirmation (e.g. 2FA). // // Only applicable when status is selected. // It may contain withdrawal operation id confirm_transfer_url?: string; } } export namespace TalerCorebankApi { export interface IntegrationConfig { // libtool-style representation of the Bank protocol version, see // https://www.gnu.org/software/libtool/manual/html_node/Versioning.html#Versioning // The format is "current:revision:age". version: string; currency: string; // How the bank SPA should render this currency. currency_specification: CurrencySpecification; // Name of the API. name: "taler-bank-integration"; } export interface Config { // Name of this API, always "taler-corebank". name: "libeufin-bank"; // name: "taler-corebank"; // API version in the form $n:$n:$n version: string; // If 'true' the server provides local currency conversion support // If 'false' some parts of the API are not supported and return 501 allow_conversion: boolean; // If 'true' anyone can register // If 'false' only the admin can allow_registrations: boolean; // Default debt limit for newly created accounts default_debit_threshold: AmountString; // If 'true' account can delete themselves // If 'false' only the admin can delete accounts allow_deletions: boolean; // Currency used by this bank. currency: string; // How the bank SPA should render this currency. currency_specification: CurrencySpecification; } export interface BankAccountCreateWithdrawalRequest { // Amount to withdraw. amount: AmountString; } export interface BankAccountCreateWithdrawalResponse { // ID of the withdrawal, can be used to view/modify the withdrawal operation. withdrawal_id: string; // URI that can be passed to the wallet to initiate the withdrawal. taler_withdraw_uri: TalerActionString; } export interface WithdrawalPublicInfo { // Current status of the operation // pending: the operation is pending parameters selection (exchange and reserve public key) // selected: the operations has been selected and is pending confirmation // aborted: the operation has been aborted // confirmed: the transfer has been confirmed and registered by the bank status: WithdrawalOperationStatus; // Amount that will be withdrawn with this operation // (raw amount without fee considerations). amount: AmountString; // Account username username: string; // Reserve public key selected by the exchange, // only non-null if status is selected or confirmed. selected_reserve_pub?: string; // Exchange account selected by the wallet // only non-null if status is selected or confirmed. selected_exchange_account?: PaytoString; } export interface BankAccountTransactionsResponse { transactions: BankAccountTransactionInfo[]; } export interface BankAccountTransactionInfo { creditor_payto_uri: PaytoString; debtor_payto_uri: PaytoString; amount: AmountString; direction: "debit" | "credit"; subject: string; // Transaction unique ID. Matches // $transaction_id from the URI. row_id: number; date: Timestamp; } export interface CreateTransactionRequest { // Address in the Payto format of the wire transfer receiver. // It needs at least the 'message' query string parameter. payto_uri: PaytoString; // Transaction amount (in the $currency:x.y format), optional. // However, when not given, its value must occupy the 'amount' // query string parameter of the 'payto' field. In case it // is given in both places, the paytoUri's takes the precedence. amount?: AmountString; } export interface CreateTransactionResponse { // ID identifying the transaction being created row_id: Integer; } export interface RegisterAccountResponse { // Internal payto URI of this bank account. internal_payto_uri: PaytoString; } export interface RegisterAccountRequest { // Username username: string; // Password. password: string; // Legal name of the account owner name: string; // Defaults to false. is_public?: boolean; // Is this a taler exchange account? // If true: // - incoming transactions to the account that do not // have a valid reserve public key are automatically // - the account provides the taler-wire-gateway-api endpoints // Defaults to false. is_taler_exchange?: boolean; // Addresses where to send the TAN for transactions. // Currently only used for cashouts. // If missing, cashouts will fail. // In the future, might be used for other transactions // as well. challenge_contact_data?: ChallengeContactData; // 'payto' address of a fiat bank account. // Payments will be sent to this bank account // when the user wants to convert the regional currency // back to fiat currency outside bank. cashout_payto_uri?: PaytoString; // Internal payto URI of this bank account. // Used mostly for testing. internal_payto_uri?: PaytoString; // If present, set the max debit allowed for this user // Only admin can change this property. debit_threshold?: AmountString; } export interface ChallengeContactData { // E-Mail address email?: EmailAddress; // Phone number. phone?: PhoneNumber; } export interface AccountReconfiguration { // Addresses where to send the TAN for transactions. // Currently only used for cashouts. // If missing, cashouts will fail. // In the future, might be used for other transactions // as well. challenge_contact_data?: ChallengeContactData; // 'payto' address pointing a bank account // external to the libeufin-bank. // Payments will be sent to this bank account // when the user wants to convert the local currency // back to fiat currency outside libeufin-bank. cashout_payto_uri?: PaytoString; // Legal name associated with $username. // When missing, the old name is kept. name?: string; // If present, change the is_exchange configuration. // See RegisterAccountRequest is_taler_exchange?: boolean; // If present, change the max debit allowed for this user // Only admin can change this property. debit_threshold?: AmountString; } export interface AccountPasswordChange { // New password. new_password: string; // Old password. If present, chec that the old password matches. // Optional for admin account. old_password?: string; } export interface PublicAccountsResponse { public_accounts: PublicAccount[]; } export interface PublicAccount { payto_uri: PaytoString; balance: Balance; // The account name (=username) of the // libeufin-bank account. account_name: string; } export interface ListBankAccountsResponse { accounts: AccountMinimalData[]; } export interface Balance { amount: AmountString; credit_debit_indicator: "credit" | "debit"; } export interface AccountMinimalData { // Username username: string; // Legal name of the account owner. name: string; // current balance of the account balance: Balance; // Number indicating the max debit allowed for the requesting user. debit_threshold: AmountString; } export interface AccountData { // Legal name of the account owner. name: string; // Available balance on the account. balance: Balance; // payto://-URI of the account. payto_uri: PaytoString; // Number indicating the max debit allowed for the requesting user. debit_threshold: AmountString; contact_data?: ChallengeContactData; // 'payto' address pointing the bank account // where to send cashouts. This field is optional // because not all the accounts are required to participate // in the merchants' circuit. One example is the exchange: // that never cashouts. Registering these accounts can // be done via the access API. cashout_payto_uri?: PaytoString; } export interface CashoutRequest { // Nonce to make the request idempotent. Requests with the same // request_uid that differ in any of the other fields // are rejected. request_uid: ShortHashCode; // Optional subject to associate to the // cashout operation. This data will appear // as the incoming wire transfer subject in // the user's fiat bank account. subject?: string; // That is the plain amount that the user specified // to cashout. Its $currency is the (regional) currency of the // bank instance. amount_debit: AmountString; // That is the amount that will effectively be // transferred by the bank to the user's bank // account, that is external to the regional currency. // It is expressed in the fiat currency and // is calculated after the cashout fee and the // exchange rate. See the /cashout-rates call. // The client needs to calculate this amount // correctly based on the amount_debit and the cashout rate, // otherwise the request will fail. amount_credit: AmountString; // Which channel the TAN should be sent to. If // this field is missing, it defaults to SMS. // The default choice prefers to change the communication // channel respect to the one used to issue this request. tan_channel?: TanChannel; } export interface CashoutPending { // ID identifying the operation being created // and now waiting for the TAN confirmation. cashout_id: number; } export interface CashoutConfirmRequest { // the TAN that confirms $CASHOUT_ID. tan: string; } export interface Cashouts { // Every string represents a cash-out operation ID. cashouts: CashoutInfo[]; } export interface CashoutInfo { cashout_id: number; status: "pending" | "aborted" | "confirmed"; } export interface GlobalCashouts { // Every string represents a cash-out operation ID. cashouts: GlobalCashoutInfo[]; } export interface GlobalCashoutInfo { cashout_id: number; username: string; status: "pending" | "aborted" | "confirmed"; } export interface CashoutStatusResponse { status: "pending" | "aborted" | "confirmed"; // Amount debited to the internal // regional currency bank account. amount_debit: AmountString; // Amount credited to the external bank account. amount_credit: AmountString; // Transaction subject. subject: string; // Fiat bank account that will receive the cashed out amount. // Specified as a payto URI. // credit_payto_uri: PaytoString; // Time when the cashout was created. creation_time: Timestamp; // Time when the cashout was confirmed via its TAN. // Missing when the operation wasn't confirmed yet. confirmation_time?: Timestamp; // Channel of the last successful transmission of the TAN challenge. // Missing when all transmissions failed. tan_channel?: TanChannel; // Info of the last successful transmission of the TAN challenge. // Missing when all transmissions failed. tan_info?: string; } export interface ConversionRatesResponse { // Exchange rate to buy the local currency from the external one buy_at_ratio: DecimalNumber; // Exchange rate to sell the local currency for the external one sell_at_ratio: DecimalNumber; // Fee to subtract after applying the buy ratio. buy_in_fee: DecimalNumber; // Fee to subtract after applying the sell ratio. sell_out_fee: DecimalNumber; } export enum MonitorTimeframeParam { hour, day, month, year, decade, } export type MonitorResponse = MonitorNoConversion | MonitorWithConversion; // Monitoring stats when conversion is not supported export interface MonitorNoConversion { type: "no-conversions"; // How many payments were made to a Taler exchange by another // bank account. talerInCount: number; // Overall volume that has been paid to a Taler // exchange by another bank account. talerInVolume: AmountString; // How many payments were made by a Taler exchange to another // bank account. talerOutCount: number; // Overall volume that has been paid by a Taler // exchange to another bank account. talerOutVolume: AmountString; } // Monitoring stats when conversion is supported export interface MonitorWithConversion { type: "with-conversions"; // How many cashin operations were confirmed by a // wallet owner. Note: wallet owners // are NOT required to be customers of the libeufin-bank. cashinCount: number; // Overall regional currency that has been paid by the regional admin account // to regional bank accounts to fulfill all the confirmed cashin operations. cashinRegionalVolume: AmountString; // Overall fiat currency that has been paid to the fiat admin account // by fiat bank accounts to fulfill all the confirmed cashin operations. cashinFiatVolume: AmountString; // How many cashout operations were confirmed. cashoutCount: number; // Overall regional currency that has been paid to the regional admin account // by fiat bank accounts to fulfill all the confirmed cashout operations. cashoutRegionalVolume: AmountString; // Overall fiat currency that has been paid by the fiat admin account // to fiat bank accounts to fulfill all the confirmed cashout operations. cashoutFiatVolume: AmountString; // How many payments were made to a Taler exchange by another // bank account. talerInCount: number; // Overall volume that has been paid to a Taler // exchange by another bank account. talerInVolume: AmountString; // How many payments were made by a Taler exchange to another // bank account. talerOutCount: number; // Overall volume that has been paid by a Taler // exchange to another bank account. talerOutVolume: AmountString; } } export namespace TalerExchangeApi { export enum AmlState { normal = 0, pending = 1, frozen = 2, } export interface AmlRecords { // Array of AML records matching the query. records: AmlRecord[]; } export interface AmlRecord { // Which payto-address is this record about. // Identifies a GNU Taler wallet or an affected bank account. h_payto: PaytoHash; // What is the current AML state. current_state: AmlState; // Monthly transaction threshold before a review will be triggered threshold: AmountString; // RowID of the record. rowid: Integer; } export interface AmlDecisionDetails { // Array of AML decisions made for this account. Possibly // contains only the most recent decision if "history" was // not set to 'true'. aml_history: AmlDecisionDetail[]; // Array of KYC attributes obtained for this account. kyc_attributes: KycDetail[]; } export interface AmlDecisionDetail { // What was the justification given? justification: string; // What is the new AML state. new_state: Integer; // When was this decision made? decision_time: Timestamp; // What is the new AML decision threshold (in monthly transaction volume)? new_threshold: AmountString; // Who made the decision? decider_pub: AmlOfficerPublicKeyP; } export interface KycDetail { // Name of the configuration section that specifies the provider // which was used to collect the KYC details provider_section: string; // The collected KYC data. NULL if the attribute data could not // be decrypted (internal error of the exchange, likely the // attribute key was changed). attributes?: Object; // Time when the KYC data was collected collection_time: Timestamp; // Time when the validity of the KYC data will expire expiration_time: Timestamp; } export interface AmlDecision { // Human-readable justification for the decision. justification: string; // At what monthly transaction volume should the // decision be automatically reviewed? new_threshold: AmountString; // Which payto-address is the decision about? // Identifies a GNU Taler wallet or an affected bank account. h_payto: PaytoHash; // What is the new AML state (e.g. frozen, unfrozen, etc.) // Numerical values are defined in AmlDecisionState. new_state: Integer; // Signature by the AML officer over a // TALER_MasterAmlOfficerStatusPS. // Must have purpose TALER_SIGNATURE_MASTER_AML_KEY. officer_sig: EddsaSignature; // When was the decision made? decision_time: Timestamp; // Optional argument to impose new KYC requirements // that the customer has to satisfy to unblock transactions. kyc_requirements?: string[]; } export interface ExchangeVersionResponse { // libtool-style representation of the Exchange protocol version, see // https://www.gnu.org/software/libtool/manual/html_node/Versioning.html#Versioning // The format is "current:revision:age". version: string; // Name of the protocol. name: "taler-exchange"; // Currency supported by this exchange. currency: string; // How wallets should render this currency. currency_specification: CurrencySpecification; // Names of supported KYC requirements. supported_kyc_requirements: string[]; } export type AccountRestriction = | RegexAccountRestriction | DenyAllAccountRestriction; // Account restriction that disables this type of // account for the indicated operation categorically. export interface DenyAllAccountRestriction { type: "deny"; } // Accounts interacting with this type of account // restriction must have a payto://-URI matching // the given regex. export interface RegexAccountRestriction { type: "regex"; // Regular expression that the payto://-URI of the // partner account must follow. The regular expression // should follow posix-egrep, but without support for character // classes, GNU extensions, back-references or intervals. See // https://www.gnu.org/software/findutils/manual/html_node/find_html/posix_002degrep-regular-expression-syntax.html // for a description of the posix-egrep syntax. Applications // may support regexes with additional features, but exchanges // must not use such regexes. payto_regex: string; // Hint for a human to understand the restriction // (that is hopefully easier to comprehend than the regex itself). human_hint: string; // Map from IETF BCP 47 language tags to localized // human hints. human_hint_i18n?: { [lang_tag: string]: string }; } export interface WireAccount { // payto:// URI identifying the account and wire method payto_uri: PaytoString; // URI to convert amounts from or to the currency used by // this wire account of the exchange. Missing if no // conversion is applicable. conversion_url?: string; // Restrictions that apply to bank accounts that would send // funds to the exchange (crediting this exchange bank account). // Optional, empty array for unrestricted. credit_restrictions: AccountRestriction[]; // Restrictions that apply to bank accounts that would receive // funds from the exchange (debiting this exchange bank account). // Optional, empty array for unrestricted. debit_restrictions: AccountRestriction[]; // Signature using the exchange's offline key over // a TALER_MasterWireDetailsPS // with purpose TALER_SIGNATURE_MASTER_WIRE_DETAILS. master_sig: EddsaSignature; } } export namespace TalerMerchantApi { export interface VersionResponse { // libtool-style representation of the Merchant protocol version, see // https://www.gnu.org/software/libtool/manual/html_node/Versioning.html#Versioning // The format is "current:revision:age". version: string; // Name of the protocol. name: "taler-merchant"; // Default (!) currency supported by this backend. // This is the currency that the backend should // suggest by default to the user when entering // amounts. See currencies for a list of // supported currencies and how to render them. currency: string; // How wallets should render currencies supported // by this backend. Maps // currency codes (e.g. "EUR" or "KUDOS") to // the respective currency specification. // All currencies in this map are supported by // the backend. currencies: { [currency: string]: CurrencySpecification }; } export interface ClaimRequest { // Nonce to identify the wallet that claimed the order. nonce: string; // Token that authorizes the wallet to claim the order. // *Optional* as the merchant may not have required it // (create_token set to false in PostOrderRequest). token?: ClaimToken; } export interface ClaimResponse { // Contract terms of the claimed order contract_terms: ContractTerms; // Signature by the merchant over the contract terms. sig: EddsaSignature; } export interface PaymentResponse { // Signature on TALER_PaymentResponsePS with the public // key of the merchant instance. sig: EddsaSignature; // Text to be shown to the point-of-sale staff as a proof of // payment. pos_confirmation?: string; } interface PayRequest { // The coins used to make the payment. coins: CoinPaySig[]; // Custom inputs from the wallet for the contract. wallet_data?: Object; // The session for which the payment is made (or replayed). // Only set for session-based payments. session_id?: string; } export interface CoinPaySig { // Signature by the coin. coin_sig: EddsaSignature; // Public key of the coin being spent. coin_pub: EddsaPublicKey; // Signature made by the denomination public key. ub_sig: RsaSignature; // The hash of the denomination public key associated with this coin. h_denom: HashCode; // The amount that is subtracted from this coin with this payment. contribution: AmountString; // URL of the exchange this coin was withdrawn from. exchange_url: string; } interface StatusPaid { // Was the payment refunded (even partially, via refund or abort)? refunded: boolean; // Is any amount of the refund still waiting to be picked up (even partially)? refund_pending: boolean; // Amount that was refunded in total. refund_amount: AmountString; // Amount that already taken by the wallet. refund_taken: AmountString; } interface StatusGotoResponse { // The client should go to the reorder URL, there a fresh // order might be created as this one is taken by another // customer or wallet (or repurchase detection logic may // apply). public_reorder_url: string; } interface StatusUnpaidResponse { // URI that the wallet must process to complete the payment. taler_pay_uri: string; // Status URL, can be used as a redirect target for the browser // to show the order QR code / trigger the wallet. fulfillment_url?: string; // Alternative order ID which was paid for already in the same session. // Only given if the same product was purchased before in the same session. already_paid_order_id?: string; } interface PaidRefundStatusResponse { // Text to be shown to the point-of-sale staff as a proof of // payment (present only if re-usable OTP algorithm is used). pos_confirmation?: string; // True if the order has been subjected to // refunds. False if it was simply paid. refunded: boolean; } interface PaidRequest { // Signature on TALER_PaymentResponsePS with the public // key of the merchant instance. sig: EddsaSignature; // Hash of the order's contract terms (this is used to authenticate the // wallet/customer and to enable signature verification without // database access). h_contract: HashCode; // Hash over custom inputs from the wallet for the contract. wallet_data_hash?: HashCode; // Session id for which the payment is proven. session_id: string; } interface AbortRequest { // Hash of the order's contract terms (this is used to authenticate the // wallet/customer in case $ORDER_ID is guessable). h_contract: HashCode; // List of coins the wallet would like to see refunds for. // (Should be limited to the coins for which the original // payment succeeded, as far as the wallet knows.) coins: AbortingCoin[]; } interface AbortingCoin { // Public key of a coin for which the wallet is requesting an abort-related refund. coin_pub: EddsaPublicKey; // The amount to be refunded (matches the original contribution) contribution: AmountString; // URL of the exchange this coin was withdrawn from. exchange_url: string; } interface AbortResponse { // List of refund responses about the coins that the wallet // requested an abort for. In the same order as the coins // from the original request. // The rtransaction_id is implied to be 0. refunds: MerchantAbortPayRefundStatus[]; } type MerchantAbortPayRefundStatus = | MerchantAbortPayRefundSuccessStatus | MerchantAbortPayRefundFailureStatus; // Details about why a refund failed. interface MerchantAbortPayRefundFailureStatus { // Used as tag for the sum type RefundStatus sum type. type: "failure"; // HTTP status of the exchange request, must NOT be 200. exchange_status: Integer; // Taler error code from the exchange reply, if available. exchange_code?: Integer; // If available, HTTP reply from the exchange. exchange_reply?: Object; } // Additional details needed to verify the refund confirmation signature // (h_contract_terms and merchant_pub) are already known // to the wallet and thus not included. interface MerchantAbortPayRefundSuccessStatus { // Used as tag for the sum type MerchantCoinRefundStatus sum type. type: "success"; // HTTP status of the exchange request, 200 (integer) required for refund confirmations. exchange_status: 200; // The EdDSA :ref:signature (binary-only) with purpose // TALER_SIGNATURE_EXCHANGE_CONFIRM_REFUND using a current signing key of the // exchange affirming the successful refund. exchange_sig: EddsaSignature; // Public EdDSA key of the exchange that was used to generate the signature. // Should match one of the exchange's signing keys from /keys. It is given // explicitly as the client might otherwise be confused by clock skew as to // which signing key was used. exchange_pub: EddsaPublicKey; } interface WalletRefundRequest { // Hash of the order's contract terms (this is used to authenticate the // wallet/customer). h_contract: HashCode; } interface WalletRefundResponse { // Amount that was refunded in total. refund_amount: AmountString; // Successful refunds for this payment, empty array for none. refunds: MerchantCoinRefundStatus[]; // Public key of the merchant. merchant_pub: EddsaPublicKey; } type MerchantCoinRefundStatus = | MerchantCoinRefundSuccessStatus | MerchantCoinRefundFailureStatus; // Details about why a refund failed. interface MerchantCoinRefundFailureStatus { // Used as tag for the sum type RefundStatus sum type. type: "failure"; // HTTP status of the exchange request, must NOT be 200. exchange_status: Integer; // Taler error code from the exchange reply, if available. exchange_code?: Integer; // If available, HTTP reply from the exchange. exchange_reply?: Object; // Refund transaction ID. rtransaction_id: Integer; // Public key of a coin that was refunded. coin_pub: EddsaPublicKey; // Amount that was refunded, including refund fee charged by the exchange // to the customer. refund_amount: AmountString; // Timestamp when the merchant approved the refund. // Useful for grouping refunds. execution_time: Timestamp; } // Additional details needed to verify the refund confirmation signature // (h_contract_terms and merchant_pub) are already known // to the wallet and thus not included. interface MerchantCoinRefundSuccessStatus { // Used as tag for the sum type MerchantCoinRefundStatus sum type. type: "success"; // HTTP status of the exchange request, 200 (integer) required for refund confirmations. exchange_status: 200; // The EdDSA :ref:signature (binary-only) with purpose // TALER_SIGNATURE_EXCHANGE_CONFIRM_REFUND using a current signing key of the // exchange affirming the successful refund. exchange_sig: EddsaSignature; // Public EdDSA key of the exchange that was used to generate the signature. // Should match one of the exchange's signing keys from /keys. It is given // explicitly as the client might otherwise be confused by clock skew as to // which signing key was used. exchange_pub: EddsaPublicKey; // Refund transaction ID. rtransaction_id: Integer; // Public key of a coin that was refunded. coin_pub: EddsaPublicKey; // Amount that was refunded, including refund fee charged by the exchange // to the customer. refund_amount: AmountString; // Timestamp when the merchant approved the refund. // Useful for grouping refunds. execution_time: Timestamp; } interface RewardInformation { // Exchange from which the reward will be withdrawn. Needed by the // wallet to determine denominations, fees, etc. exchange_url: string; // URL where to go after obtaining the reward. next_url: string; // (Remaining) amount of the reward (including fees). reward_amount: AmountString; // Timestamp indicating when the reward is set to expire (may be in the past). // Note that rewards that have expired MAY also result in a 404 response. expiration: Timestamp; } interface RewardPickupRequest { // List of planchets the wallet wants to use for the reward. planchets: PlanchetDetail[]; } interface PlanchetDetail { // Hash of the denomination's public key (hashed to reduce // bandwidth consumption). denom_pub_hash: HashCode; // Coin's blinded public key. coin_ev: CoinEnvelope; } interface RewardResponse { // Blind RSA signatures over the planchets. // The order of the signatures matches the planchets list. blind_sigs: BlindSignature[]; } interface BlindSignature { // The (blind) RSA signature. Still needs to be unblinded. blind_sig: BlindedRsaSignature; } interface InstanceConfigurationMessage { // Name of the merchant instance to create (will become $INSTANCE). // Must match the regex ^[A-Za-z0-9][A-Za-z0-9_.@-]+$. id: string; // Merchant name corresponding to this instance. name: string; // Type of the user (business or individual). // Defaults to 'business'. Should become mandatory field // in the future, left as optional for API compatibility for now. user_type?: string; // Merchant email for customer contact. email?: string; // Merchant public website. website?: string; // Merchant logo. logo?: ImageDataUrl; // Authentication settings for this instance auth: InstanceAuthConfigurationMessage; // The merchant's physical address (to be put into contracts). address: Location; // The jurisdiction under which the merchant conducts its business // (to be put into contracts). jurisdiction: Location; // Use STEFAN curves to determine default fees? // If false, no fees are allowed by default. // Can always be overridden by the frontend on a per-order basis. use_stefan: boolean; // If the frontend does NOT specify an execution date, how long should // we tell the exchange to wait to aggregate transactions before // executing the wire transfer? This delay is added to the current // time when we generate the advisory execution time for the exchange. default_wire_transfer_delay: RelativeTime; // If the frontend does NOT specify a payment deadline, how long should // offers we make be valid by default? default_pay_delay: RelativeTime; } interface InstanceAuthConfigurationMessage { // Type of authentication. // "external": The mechant backend does not do // any authentication checks. Instead an API // gateway must do the authentication. // "token": The merchant checks an auth token. // See "token" for details. method: "external" | "token"; // For method "token", this field is mandatory. // The token MUST begin with the string "secret-token:". // After the auth token has been set (with method "token"), // the value must be provided in a "Authorization: Bearer $token" // header. token?: string; } interface LoginTokenRequest { // Scope of the token (which kinds of operations it will allow) scope: "readonly" | "write"; // Server may impose its own upper bound // on the token validity duration duration?: RelativeTime; // Can this token be refreshed? // Defaults to false. refreshable?: boolean; } interface LoginTokenSuccessResponse { // The login token that can be used to access resources // that are in scope for some time. Must be prefixed // with "Bearer " when used in the "Authorization" HTTP header. // Will already begin with the RFC 8959 prefix. token: string; // Scope of the token (which kinds of operations it will allow) scope: "readonly" | "write"; // Server may impose its own upper bound // on the token validity duration expiration: Timestamp; // Can this token be refreshed? refreshable: boolean; } interface InstanceReconfigurationMessage { // Merchant name corresponding to this instance. name: string; // Type of the user (business or individual). // Defaults to 'business'. Should become mandatory field // in the future, left as optional for API compatibility for now. user_type?: string; // Merchant email for customer contact. email?: string; // Merchant public website. website?: string; // Merchant logo. logo?: ImageDataUrl; // The merchant's physical address (to be put into contracts). address: Location; // The jurisdiction under which the merchant conducts its business // (to be put into contracts). jurisdiction: Location; // Use STEFAN curves to determine default fees? // If false, no fees are allowed by default. // Can always be overridden by the frontend on a per-order basis. use_stefan: boolean; // If the frontend does NOT specify an execution date, how long should // we tell the exchange to wait to aggregate transactions before // executing the wire transfer? This delay is added to the current // time when we generate the advisory execution time for the exchange. default_wire_transfer_delay: RelativeTime; // If the frontend does NOT specify a payment deadline, how long should // offers we make be valid by default? default_pay_delay: RelativeTime; } interface InstancesResponse { // List of instances that are present in the backend (see Instance). instances: Instance[]; } interface Instance { // Merchant name corresponding to this instance. name: string; // Type of the user ("business" or "individual"). user_type: string; // Merchant public website. website?: string; // Merchant logo. logo?: ImageDataUrl; // Merchant instance this response is about ($INSTANCE). id: string; // Public key of the merchant/instance, in Crockford Base32 encoding. merchant_pub: EddsaPublicKey; // List of the payment targets supported by this instance. Clients can // specify the desired payment target in /order requests. Note that // front-ends do not have to support wallets selecting payment targets. payment_targets: string[]; // Has this instance been deleted (but not purged)? deleted: boolean; } interface QueryInstancesResponse { // Merchant name corresponding to this instance. name: string; // Type of the user ("business" or "individual"). user_type: string; // Merchant email for customer contact. email?: string; // Merchant public website. website?: string; // Merchant logo. logo?: ImageDataUrl; // Public key of the merchant/instance, in Crockford Base32 encoding. merchant_pub: EddsaPublicKey; // The merchant's physical address (to be put into contracts). address: Location; // The jurisdiction under which the merchant conducts its business // (to be put into contracts). jurisdiction: Location; // Use STEFAN curves to determine default fees? // If false, no fees are allowed by default. // Can always be overridden by the frontend on a per-order basis. use_stefan: boolean; // If the frontend does NOT specify an execution date, how long should // we tell the exchange to wait to aggregate transactions before // executing the wire transfer? This delay is added to the current // time when we generate the advisory execution time for the exchange. default_wire_transfer_delay: RelativeTime; // If the frontend does NOT specify a payment deadline, how long should // offers we make be valid by default? default_pay_delay: RelativeTime; // Authentication configuration. // Does not contain the token when token auth is configured. auth: { type: "external" | "token"; }; } interface AccountKycRedirects { // Array of pending KYCs. pending_kycs: MerchantAccountKycRedirect[]; // Array of exchanges with no reply. timeout_kycs: ExchangeKycTimeout[]; } interface MerchantAccountKycRedirect { // URL that the user should open in a browser to // proceed with the KYC process (as returned // by the exchange's /kyc-check/ endpoint). // Optional, missing if the account is blocked // due to AML and not due to KYC. kyc_url?: string; // AML status of the account. aml_status: Integer; // Base URL of the exchange this is about. exchange_url: string; // Our bank wire account this is about. payto_uri: PaytoString; } interface ExchangeKycTimeout { // Base URL of the exchange this is about. exchange_url: string; // Numeric error code indicating errors the exchange // returned, or TALER_EC_INVALID for none. exchange_code: number; // HTTP status code returned by the exchange when we asked for // information about the KYC status. // 0 if there was no response at all. exchange_http_status: number; } interface AccountAddDetails { // payto:// URI of the account. payto_uri: PaytoString; // URL from where the merchant can download information // about incoming wire transfers to this account. credit_facade_url?: string; // Credentials to use when accessing the credit facade. // Never returned on a GET (as this may be somewhat // sensitive data). Can be set in POST // or PATCH requests to update (or delete) credentials. // To really delete credentials, set them to the type: "none". credit_facade_credentials?: FacadeCredentials; } type FacadeCredentials = NoFacadeCredentials | BasicAuthFacadeCredentials; interface NoFacadeCredentials { type: "none"; } interface BasicAuthFacadeCredentials { type: "basic"; // Username to use to authenticate username: string; // Password to use to authenticate password: string; } interface AccountAddResponse { // Hash over the wire details (including over the salt). h_wire: HashCode; // Salt used to compute h_wire. salt: HashCode; } interface AccountPatchDetails { // URL from where the merchant can download information // about incoming wire transfers to this account. credit_facade_url?: string; // Credentials to use when accessing the credit facade. // Never returned on a GET (as this may be somewhat // sensitive data). Can be set in POST // or PATCH requests to update (or delete) credentials. // To really delete credentials, set them to the type: "none". // If the argument is omitted, the old credentials // are simply preserved. credit_facade_credentials?: FacadeCredentials; } interface AccountsSummaryResponse { // List of accounts that are known for the instance. accounts: BankAccountEntry[]; } interface BankAccountEntry { // payto:// URI of the account. payto_uri: PaytoString; // Hash over the wire details (including over the salt). h_wire: HashCode; // Salt used to compute h_wire. salt: HashCode; // URL from where the merchant can download information // about incoming wire transfers to this account. credit_facade_url?: string; // true if this account is active, // false if it is historic. active: boolean; } interface ProductAddDetail { // Product ID to use. product_id: string; // Human-readable product description. description: string; // Map from IETF BCP 47 language tags to localized descriptions. description_i18n?: { [lang_tag: string]: string }; // Unit in which the product is measured (liters, kilograms, packages, etc.). unit: string; // The price for one unit of the product. Zero is used // to imply that this product is not sold separately, or // that the price is not fixed, and must be supplied by the // front-end. If non-zero, this price MUST include applicable // taxes. price: AmountString; // An optional base64-encoded product image. image?: ImageDataUrl; // A list of taxes paid by the merchant for one unit of this product. taxes?: Tax[]; // Number of units of the product in stock in sum in total, // including all existing sales ever. Given in product-specific // units. // A value of -1 indicates "infinite" (i.e. for "electronic" books). total_stock: Integer; // Identifies where the product is in stock. address?: Location; // Identifies when we expect the next restocking to happen. next_restock?: Timestamp; // Minimum age buyer must have (in years). Default is 0. minimum_age?: Integer; } interface ProductPatchDetail { // Human-readable product description. description: string; // Map from IETF BCP 47 language tags to localized descriptions. description_i18n?: { [lang_tag: string]: string }; // Unit in which the product is measured (liters, kilograms, packages, etc.). unit: string; // The price for one unit of the product. Zero is used // to imply that this product is not sold separately, or // that the price is not fixed, and must be supplied by the // front-end. If non-zero, this price MUST include applicable // taxes. price: AmountString; // An optional base64-encoded product image. image?: ImageDataUrl; // A list of taxes paid by the merchant for one unit of this product. taxes?: Tax[]; // Number of units of the product in stock in sum in total, // including all existing sales ever. Given in product-specific // units. // A value of -1 indicates "infinite" (i.e. for "electronic" books). total_stock: Integer; // Number of units of the product that were lost (spoiled, stolen, etc.). total_lost?: Integer; // Identifies where the product is in stock. address?: Location; // Identifies when we expect the next restocking to happen. next_restock?: Timestamp; // Minimum age buyer must have (in years). Default is 0. minimum_age?: Integer; } interface InventorySummaryResponse { // List of products that are present in the inventory. products: InventoryEntry[]; } interface InventoryEntry { // Product identifier, as found in the product. product_id: string; } interface ProductDetail { // Human-readable product description. description: string; // Map from IETF BCP 47 language tags to localized descriptions. description_i18n: { [lang_tag: string]: string }; // Unit in which the product is measured (liters, kilograms, packages, etc.). unit: string; // The price for one unit of the product. Zero is used // to imply that this product is not sold separately, or // that the price is not fixed, and must be supplied by the // front-end. If non-zero, this price MUST include applicable // taxes. price: AmountString; // An optional base64-encoded product image. image: ImageDataUrl; // A list of taxes paid by the merchant for one unit of this product. taxes: Tax[]; // Number of units of the product in stock in sum in total, // including all existing sales ever. Given in product-specific // units. // A value of -1 indicates "infinite" (i.e. for "electronic" books). total_stock: Integer; // Number of units of the product that have already been sold. total_sold: Integer; // Number of units of the product that were lost (spoiled, stolen, etc.). total_lost: Integer; // Identifies where the product is in stock. address: Location; // Identifies when we expect the next restocking to happen. next_restock?: Timestamp; // Minimum age buyer must have (in years). minimum_age?: Integer; } interface LockRequest { // UUID that identifies the frontend performing the lock // Must be unique for the lifetime of the lock. lock_uuid: string; // How long does the frontend intend to hold the lock? duration: RelativeTime; // How many units should be locked? quantity: Integer; } interface PostOrderRequest { // The order must at least contain the minimal // order detail, but can override all. order: Order; // If set, the backend will then set the refund deadline to the current // time plus the specified delay. If it's not set, refunds will not be // possible. refund_delay?: RelativeTime; // Specifies the payment target preferred by the client. Can be used // to select among the various (active) wire methods supported by the instance. payment_target?: string; // Specifies that some products are to be included in the // order from the inventory. For these inventory management // is performed (so the products must be in stock) and // details are completed from the product data of the backend. inventory_products?: MinimalInventoryProduct[]; // Specifies a lock identifier that was used to // lock a product in the inventory. Only useful if // inventory_products is set. Used in case a frontend // reserved quantities of the individual products while // the shopping cart was being built. Multiple UUIDs can // be used in case different UUIDs were used for different // products (i.e. in case the user started with multiple // shopping sessions that were combined during checkout). lock_uuids: string[]; // Should a token for claiming the order be generated? // False can make sense if the ORDER_ID is sufficiently // high entropy to prevent adversarial claims (like it is // if the backend auto-generates one). Default is 'true'. create_token?: boolean; // OTP device ID to associate with the order. // This parameter is optional. otp_id?: string; } type Order = MinimalOrderDetail | ContractTerms; interface MinimalOrderDetail { // Amount to be paid by the customer. amount: AmountString; // Short summary of the order. summary: string; // See documentation of fulfillment_url in ContractTerms. // Either fulfillment_url or fulfillment_message must be specified. fulfillment_url?: string; // See documentation of fulfillment_message in ContractTerms. // Either fulfillment_url or fulfillment_message must be specified. fulfillment_message?: string; } interface MinimalInventoryProduct { // Which product is requested (here mandatory!). product_id: string; // How many units of the product are requested. quantity: Integer; } interface PostOrderResponse { // Order ID of the response that was just created. order_id: string; // Token that authorizes the wallet to claim the order. // Provided only if "create_token" was set to 'true' // in the request. token?: ClaimToken; } interface OutOfStockResponse { // Product ID of an out-of-stock item. product_id: string; // Requested quantity. requested_quantity: Integer; // Available quantity (must be below requested_quantity). available_quantity: Integer; // When do we expect the product to be again in stock? // Optional, not given if unknown. restock_expected?: Timestamp; } interface OrderHistory { // Timestamp-sorted array of all orders matching the query. // The order of the sorting depends on the sign of delta. orders: OrderHistoryEntry[]; } interface OrderHistoryEntry { // Order ID of the transaction related to this entry. order_id: string; // Row ID of the order in the database. row_id: number; // When the order was created. timestamp: Timestamp; // The amount of money the order is for. amount: AmountString; // The summary of the order. summary: string; // Whether some part of the order is refundable, // that is the refund deadline has not yet expired // and the total amount refunded so far is below // the value of the original transaction. refundable: boolean; // Whether the order has been paid or not. paid: boolean; } type MerchantOrderStatusResponse = | CheckPaymentPaidResponse | CheckPaymentClaimedResponse | CheckPaymentUnpaidResponse; interface CheckPaymentPaidResponse { // The customer paid for this contract. order_status: "paid"; // Was the payment refunded (even partially)? refunded: boolean; // True if there are any approved refunds that the wallet has // not yet obtained. refund_pending: boolean; // Did the exchange wire us the funds? wired: boolean; // Total amount the exchange deposited into our bank account // for this contract, excluding fees. deposit_total: AmountString; // Numeric error code indicating errors the exchange // encountered tracking the wire transfer for this purchase (before // we even got to specific coin issues). // 0 if there were no issues. exchange_code: number; // HTTP status code returned by the exchange when we asked for // information to track the wire transfer for this purchase. // 0 if there were no issues. exchange_http_status: number; // Total amount that was refunded, 0 if refunded is false. refund_amount: AmountString; // Contract terms. contract_terms: ContractTerms; // The wire transfer status from the exchange for this order if // available, otherwise empty array. wire_details: TransactionWireTransfer[]; // Reports about trouble obtaining wire transfer details, // empty array if no trouble were encountered. wire_reports: TransactionWireReport[]; // The refund details for this order. One entry per // refunded coin; empty array if there are no refunds. refund_details: RefundDetails[]; // Status URL, can be used as a redirect target for the browser // to show the order QR code / trigger the wallet. order_status_url: string; } interface CheckPaymentClaimedResponse { // A wallet claimed the order, but did not yet pay for the contract. order_status: "claimed"; // Contract terms. contract_terms: ContractTerms; } interface CheckPaymentUnpaidResponse { // The order was neither claimed nor paid. order_status: "unpaid"; // URI that the wallet must process to complete the payment. taler_pay_uri: string; // when was the order created creation_time: Timestamp; // Order summary text. summary: string; // Total amount of the order (to be paid by the customer). total_amount: AmountString; // Alternative order ID which was paid for already in the same session. // Only given if the same product was purchased before in the same session. already_paid_order_id?: string; // Fulfillment URL of an already paid order. Only given if under this // session an already paid order with a fulfillment URL exists. already_paid_fulfillment_url?: string; // Status URL, can be used as a redirect target for the browser // to show the order QR code / trigger the wallet. order_status_url: string; // We do we NOT return the contract terms here because they may not // exist in case the wallet did not yet claim them. } interface RefundDetails { // Reason given for the refund. reason: string; // Set to true if a refund is still available for the wallet for this payment. pending: boolean; // When was the refund approved. timestamp: Timestamp; // Total amount that was refunded (minus a refund fee). amount: AmountString; } interface TransactionWireTransfer { // Responsible exchange. exchange_url: string; // 32-byte wire transfer identifier. wtid: Base32; // Execution time of the wire transfer. execution_time: Timestamp; // Total amount that has been wire transferred // to the merchant. amount: AmountString; // Was this transfer confirmed by the merchant via the // POST /transfers API, or is it merely claimed by the exchange? confirmed: boolean; } interface TransactionWireReport { // Numerical error code. code: number; // Human-readable error description. hint: string; // Numerical error code from the exchange. exchange_code: number; // HTTP status code received from the exchange. exchange_http_status: number; // Public key of the coin for which we got the exchange error. coin_pub: CoinPublicKey; } interface ForgetRequest { // Array of valid JSON paths to forgettable fields in the order's // contract terms. fields: string[]; } interface RefundRequest { // Amount to be refunded. refund: AmountString; // Human-readable refund justification. reason: string; } interface MerchantRefundResponse { // URL (handled by the backend) that the wallet should access to // trigger refund processing. // taler://refund/... taler_refund_uri: string; // Contract hash that a client may need to authenticate an // HTTP request to obtain the above URI in a wallet-friendly way. h_contract: HashCode; } interface TransferInformation { // How much was wired to the merchant (minus fees). credit_amount: AmountString; // Raw wire transfer identifier identifying the wire transfer (a base32-encoded value). wtid: WireTransferIdentifierRawP; // Target account that received the wire transfer. payto_uri: PaytoString; // Base URL of the exchange that made the wire transfer. exchange_url: string; } interface TransferList { // List of all the transfers that fit the filter that we know. transfers: TransferDetails[]; } interface TransferDetails { // How much was wired to the merchant (minus fees). credit_amount: AmountString; // Raw wire transfer identifier identifying the wire transfer (a base32-encoded value). wtid: WireTransferIdentifierRawP; // Target account that received the wire transfer. payto_uri: PaytoString; // Base URL of the exchange that made the wire transfer. exchange_url: string; // Serial number identifying the transfer in the merchant backend. // Used for filtering via offset. transfer_serial_id: number; // Time of the execution of the wire transfer by the exchange, according to the exchange // Only provided if we did get an answer from the exchange. execution_time?: Timestamp; // True if we checked the exchange's answer and are happy with it. // False if we have an answer and are unhappy, missing if we // do not have an answer from the exchange. verified?: boolean; // True if the merchant uses the POST /transfers API to confirm // that this wire transfer took place (and it is thus not // something merely claimed by the exchange). confirmed?: boolean; } interface ReserveCreateRequest { // Amount that the merchant promises to put into the reserve. initial_balance: AmountString; // Exchange the merchant intends to use for rewards. exchange_url: string; // Desired wire method, for example "iban" or "x-taler-bank". wire_method: string; } interface ReserveCreateConfirmation { // Public key identifying the reserve. reserve_pub: EddsaPublicKey; // Wire accounts of the exchange where to transfer the funds. accounts: TalerExchangeApi.WireAccount[]; } interface RewardReserveStatus { // Array of all known reserves (possibly empty!). reserves: ReserveStatusEntry[]; } interface ReserveStatusEntry { // Public key of the reserve. reserve_pub: EddsaPublicKey; // Timestamp when it was established. creation_time: Timestamp; // Timestamp when it expires. expiration_time: Timestamp; // Initial amount as per reserve creation call. merchant_initial_amount: AmountString; // Initial amount as per exchange, 0 if exchange did // not confirm reserve creation yet. exchange_initial_amount: AmountString; // Amount picked up so far. pickup_amount: AmountString; // Amount approved for rewards that exceeds the pickup_amount. committed_amount: AmountString; // Is this reserve active (false if it was deleted but not purged)? active: boolean; } interface ReserveDetail { // Timestamp when it was established. creation_time: Timestamp; // Timestamp when it expires. expiration_time: Timestamp; // Initial amount as per reserve creation call. merchant_initial_amount: AmountString; // Initial amount as per exchange, 0 if exchange did // not confirm reserve creation yet. exchange_initial_amount: AmountString; // Amount picked up so far. pickup_amount: AmountString; // Amount approved for rewards that exceeds the pickup_amount. committed_amount: AmountString; // Array of all rewards created by this reserves (possibly empty!). // Only present if asked for explicitly. rewards?: RewardStatusEntry[]; // Is this reserve active (false if it was deleted but not purged)? active: boolean; // Array of wire accounts of the exchange that could // be used to fill the reserve, can be NULL // if the reserve is inactive or was already filled accounts?: TalerExchangeApi.WireAccount[]; // URL of the exchange hosting the reserve, // NULL if the reserve is inactive exchange_url: string; } interface RewardStatusEntry { // Unique identifier for the reward. reward_id: HashCode; // Total amount of the reward that can be withdrawn. total_amount: AmountString; // Human-readable reason for why the reward was granted. reason: string; } interface RewardCreateRequest { // Amount that the customer should be rewarded. amount: AmountString; // Justification for giving the reward. justification: string; // URL that the user should be directed to after receiving the reward, // will be included in the reward_token. next_url: string; } interface RewardCreateConfirmation { // Unique reward identifier for the reward that was created. reward_id: HashCode; // taler://reward URI for the reward. taler_reward_uri: string; // URL that will directly trigger processing // the reward when the browser is redirected to it. reward_status_url: string; // When does the reward expire? reward_expiration: Timestamp; } interface RewardDetails { // Amount that we authorized for this reward. total_authorized: AmountString; // Amount that was picked up by the user already. total_picked_up: AmountString; // Human-readable reason given when authorizing the reward. reason: string; // Timestamp indicating when the reward is set to expire (may be in the past). expiration: Timestamp; // Reserve public key from which the reward is funded. reserve_pub: EddsaPublicKey; // Array showing the pickup operations of the wallet (possibly empty!). // Only present if asked for explicitly. pickups?: PickupDetail[]; } interface PickupDetail { // Unique identifier for the pickup operation. pickup_id: HashCode; // Number of planchets involved. num_planchets: Integer; // Total amount requested for this pickup_id. requested_amount: AmountString; } interface RewardsResponse { // List of rewards that are present in the backend. rewards: Reward[]; } interface Reward { // ID of the reward in the backend database. row_id: number; // Unique identifier for the reward. reward_id: HashCode; // (Remaining) amount of the reward (including fees). reward_amount: AmountString; } interface OtpDeviceAddDetails { // Device ID to use. otp_device_id: string; // Human-readable description for the device. otp_device_description: string; // A base64-encoded key otp_key: string; // Algorithm for computing the POS confirmation. otp_algorithm: Integer; // Counter for counter-based OTP devices. otp_ctr?: Integer; } interface OtpDevicePatchDetails { // Human-readable description for the device. otp_device_description: string; // A base64-encoded key otp_key: string; // Algorithm for computing the POS confirmation. otp_algorithm: Integer; // Counter for counter-based OTP devices. otp_ctr?: Integer; } interface OtpDeviceSummaryResponse { // Array of devices that are present in our backend. otp_devices: OtpDeviceEntry[]; } interface OtpDeviceEntry { // Device identifier. otp_device_id: string; // Human-readable description for the device. device_description: string; } interface OtpDeviceDetails { // Human-readable description for the device. device_description: string; // Algorithm for computing the POS confirmation. otp_algorithm: Integer; // Counter for counter-based OTP devices. otp_ctr?: Integer; } interface TemplateAddDetails { // Template ID to use. template_id: string; // Human-readable description for the template. template_description: string; // OTP device ID. // This parameter is optional. otp_id?: string; // Additional information in a separate template. template_contract: TemplateContractDetails; } interface TemplateContractDetails { // Human-readable summary for the template. summary?: string; // Required currency for payments to the template. // The user may specify any amount, but it must be // in this currency. // This parameter is optional and should not be present // if "amount" is given. currency?: string; // The price is imposed by the merchant and cannot be changed by the customer. // This parameter is optional. amount?: AmountString; // Minimum age buyer must have (in years). Default is 0. minimum_age: Integer; // The time the customer need to pay before his order will be deleted. // It is deleted if the customer did not pay and if the duration is over. pay_duration: RelativeTime; } interface TemplatePatchDetails { // Human-readable description for the template. template_description: string; // OTP device ID. // This parameter is optional. otp_id?: string; // Additional information in a separate template. template_contract: TemplateContractDetails; } interface TemplateSummaryResponse { // List of templates that are present in our backend. templates_list: TemplateEntry[]; } interface TemplateEntry { // Template identifier, as found in the template. template_id: string; // Human-readable description for the template. template_description: string; } interface TemplateDetails { // Human-readable description for the template. template_description: string; // OTP device ID. // This parameter is optional. otp_id?: string; // Additional information in a separate template. template_contract: TemplateContractDetails; } interface UsingTemplateDetails { // Summary of the template summary?: string; // The amount entered by the customer. amount?: AmountString; } interface WebhookAddDetails { // Webhook ID to use. webhook_id: string; // The event of the webhook: why the webhook is used. event_type: string; // URL of the webhook where the customer will be redirected. url: string; // Method used by the webhook http_method: string; // Header template of the webhook header_template?: string; // Body template by the webhook body_template?: string; } interface WebhookPatchDetails { // The event of the webhook: why the webhook is used. event_type: string; // URL of the webhook where the customer will be redirected. url: string; // Method used by the webhook http_method: string; // Header template of the webhook header_template?: string; // Body template by the webhook body_template?: string; } interface WebhookSummaryResponse { // Return webhooks that are present in our backend. webhooks: WebhookEntry[]; } interface WebhookEntry { // Webhook identifier, as found in the webhook. webhook_id: string; // The event of the webhook: why the webhook is used. event_type: string; } interface WebhookDetails { // The event of the webhook: why the webhook is used. event_type: string; // URL of the webhook where the customer will be redirected. url: string; // Method used by the webhook http_method: string; // Header template of the webhook header_template?: string; // Body template by the webhook body_template?: string; } interface ContractTerms { // Human-readable description of the whole purchase. summary: string; // Map from IETF BCP 47 language tags to localized summaries. summary_i18n?: { [lang_tag: string]: string }; // Unique, free-form identifier for the proposal. // Must be unique within a merchant instance. // For merchants that do not store proposals in their DB // before the customer paid for them, the order_id can be used // by the frontend to restore a proposal from the information // encoded in it (such as a short product identifier and timestamp). order_id: string; // Total price for the transaction. // The exchange will subtract deposit fees from that amount // before transferring it to the merchant. amount: AmountString; // URL where the same contract could be ordered again (if // available). Returned also at the public order endpoint // for people other than the actual buyer (hence public, // in case order IDs are guessable). public_reorder_url?: string; // URL that will show that the order was successful after // it has been paid for. Optional. When POSTing to the // merchant, the placeholder "${ORDER_ID}" will be // replaced with the actual order ID (useful if the // order ID is generated server-side and needs to be // in the URL). // Note that this placeholder can only be used once. // Either fulfillment_url or fulfillment_message must be specified. fulfillment_url?: string; // Message shown to the customer after paying for the order. // Either fulfillment_url or fulfillment_message must be specified. fulfillment_message?: string; // Map from IETF BCP 47 language tags to localized fulfillment // messages. fulfillment_message_i18n?: { [lang_tag: string]: string }; // Maximum total deposit fee accepted by the merchant for this contract. // Overrides defaults of the merchant instance. max_fee: AmountString; // List of products that are part of the purchase (see Product). products: Product[]; // Time when this contract was generated. timestamp: Timestamp; // After this deadline has passed, no refunds will be accepted. refund_deadline: Timestamp; // After this deadline, the merchant won't accept payments for the contract. pay_deadline: Timestamp; // Transfer deadline for the exchange. Must be in the // deposit permissions of coins used to pay for this order. wire_transfer_deadline: Timestamp; // Merchant's public key used to sign this proposal; this information // is typically added by the backend. Note that this can be an ephemeral key. merchant_pub: EddsaPublicKey; // Base URL of the (public!) merchant backend API. // Must be an absolute URL that ends with a slash. merchant_base_url: string; // More info about the merchant, see below. merchant: Merchant; // The hash of the merchant instance's wire details. h_wire: HashCode; // Wire transfer method identifier for the wire method associated with h_wire. // The wallet may only select exchanges via a matching auditor if the // exchange also supports this wire method. // The wire transfer fees must be added based on this wire transfer method. wire_method: string; // Exchanges that the merchant accepts even if it does not accept any auditors that audit them. exchanges: Exchange[]; // Delivery location for (all!) products. delivery_location?: Location; // Time indicating when the order should be delivered. // May be overwritten by individual products. delivery_date?: Timestamp; // Nonce generated by the wallet and echoed by the merchant // in this field when the proposal is generated. nonce: string; // Specifies for how long the wallet should try to get an // automatic refund for the purchase. If this field is // present, the wallet should wait for a few seconds after // the purchase and then automatically attempt to obtain // a refund. The wallet should probe until "delay" // after the payment was successful (i.e. via long polling // or via explicit requests with exponential back-off). // // In particular, if the wallet is offline // at that time, it MUST repeat the request until it gets // one response from the merchant after the delay has expired. // If the refund is granted, the wallet MUST automatically // recover the payment. This is used in case a merchant // knows that it might be unable to satisfy the contract and // desires for the wallet to attempt to get the refund without any // customer interaction. Note that it is NOT an error if the // merchant does not grant a refund. auto_refund?: RelativeTime; // Extra data that is only interpreted by the merchant frontend. // Useful when the merchant needs to store extra information on a // contract without storing it separately in their database. extra?: any; } interface Product { // Merchant-internal identifier for the product. product_id?: string; // Human-readable product description. description: string; // Map from IETF BCP 47 language tags to localized descriptions. description_i18n?: { [lang_tag: string]: string }; // The number of units of the product to deliver to the customer. quantity?: Integer; // Unit in which the product is measured (liters, kilograms, packages, etc.). unit?: string; // The price of the product; this is the total price for quantity times unit of this product. price?: AmountString; // An optional base64-encoded product image. image?: ImageDataUrl; // A list of taxes paid by the merchant for this product. Can be empty. taxes?: Tax[]; // Time indicating when this product should be delivered. delivery_date?: Timestamp; } interface Tax { // The name of the tax. name: string; // Amount paid in tax. tax: AmountString; } interface Merchant { // The merchant's legal name of business. name: string; // Label for a location with the business address of the merchant. email?: string; // Label for a location with the business address of the merchant. website?: string; // An optional base64-encoded product image. logo?: ImageDataUrl; // Label for a location with the business address of the merchant. address?: Location; // Label for a location that denotes the jurisdiction for disputes. // Some of the typical fields for a location (such as a street address) may be absent. jurisdiction?: Location; } // Delivery location, loosely modeled as a subset of // ISO20022's PostalAddress25. interface Location { // Nation with its own government. country?: string; // Identifies a subdivision of a country such as state, region, county. country_subdivision?: string; // Identifies a subdivision within a country sub-division. district?: string; // Name of a built-up area, with defined boundaries, and a local government. town?: string; // Specific location name within the town. town_location?: string; // Identifier consisting of a group of letters and/or numbers that // is added to a postal address to assist the sorting of mail. post_code?: string; // Name of a street or thoroughfare. street?: string; // Name of the building or house. building_name?: string; // Number that identifies the position of a building on a street. building_number?: string; // Free-form address lines, should not exceed 7 elements. address_lines?: string[]; } interface Auditor { // Official name. name: string; // Auditor's public key. auditor_pub: EddsaPublicKey; // Base URL of the auditor. url: string; } interface Exchange { // The exchange's base URL. url: string; // How much would the merchant like to use this exchange. // The wallet should use a suitable exchange with high // priority. The following priority values are used, but // it should be noted that they are NOT in any way normative. // // 0: likely it will not work (recently seen with account // restriction that would be bad for this merchant) // 512: merchant does not know, might be down (merchant // did not yet get /wire response). // 1024: good choice (recently confirmed working) priority: Integer; // Master public key of the exchange. master_pub: EddsaPublicKey; } }