import { deprecate } from "util"; import { codecForAmountString } from "../amounts.js"; import { Codec, buildCodecForObject, buildCodecForUnion, codecForAny, codecForBoolean, codecForConstNumber, codecForConstString, codecForEither, codecForList, codecForMap, codecForNumber, codecForString, codecOptional, } from "../codec.js"; import { PaytoString, codecForPaytoString } from "../payto.js"; import { AmountString, codecForInternationalizedString, codecForLocation, } from "../taler-types.js"; import { TalerUriString, codecForTalerUriString } from "../taleruri.js"; import { AbsoluteTime, TalerProtocolDuration, TalerProtocolTimestamp, codecForAbsoluteTime, codecForDuration, 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; /** * order */ order?: "asc" | "dec"; }; export type LongPollParams = { /** * milliseconds the server should wait for at least one result to be shown */ timeoutMs?: number; }; /// /// 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; type Timestamp = TalerProtocolTimestamp; type RelativeTime = TalerProtocolDuration; export interface LoginToken { token: AccessToken; expiration: Timestamp; } declare const __ac_token: unique symbol; /** * Use `createAccessToken(string)` function to build one. */ export type AccessToken = string & { [__ac_token]: true; }; /** * Create a rfc8959 access token. * Adds secret-token: prefix if there is none. * * @deprecated use createRFC8959AccessToken * @param token * @returns */ export function createAccessToken(token: string): AccessToken { return ( token.startsWith("secret-token:") ? token : `secret-token:${token}` ) as AccessToken; } /** * Create a rfc8959 access token. * Adds secret-token: prefix if there is none. * * @param token * @returns */ export function createRFC8959AccessToken(token: string): AccessToken { return ( token.startsWith("secret-token:") ? token : `secret-token:${token}` ) as AccessToken; } /** * Conver string to access token. * * @param clientSecret * @returns */ export function createClientSecretAccessToken(clientSecret: string): AccessToken { return clientSecret as AccessToken; } 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; } export interface TokenSuccessResponseMerchant { // 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. 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 }; } //FIXME: implement this codec export const codecForAccessToken = codecForString as () => Codec; export const codecForTokenSuccessResponse = (): Codec => buildCodecForObject() .property("access_token", codecForAccessToken()) .property("expiration", codecForTimestamp) .build("TalerAuthentication.TokenSuccessResponse"); export const codecForTokenSuccessResponseMerchant = (): Codec => buildCodecForObject() .property("token", codecForAccessToken()) .property("expiration", codecForTimestamp) .build("TalerAuthentication.TokenSuccessResponseMerchant"); 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("bank_name", codecForString()) .property("allow_conversion", codecForBoolean()) .property("allow_registrations", codecForBoolean()) .property("allow_deletions", codecForBoolean()) .property("allow_edit_name", codecForBoolean()) .property("allow_edit_cashout_payto_uri", codecForBoolean()) .property("default_debit_threshold", codecForAmountString()) .property("currency", codecForString()) .property("currency_specification", codecForCurrencySpecificiation()) .property( "supported_tan_channels", codecForList( codecForEither( codecForConstString(TalerCorebankApi.TanChannel.SMS), codecForConstString(TalerCorebankApi.TanChannel.EMAIL), ), ), ) .property("wire_type", codecForString()) .build("TalerCorebankApi.Config"); //FIXME: implement this codec export const codecForURN = codecForString; export const codecForExchangeConfigInfo = (): Codec => buildCodecForObject() .property("base_url", codecForString()) .property("currency", codecForString()) .property("master_pub", codecForString()) .build("TalerMerchantApi.ExchangeConfigInfo"); export const codecForMerchantConfig = (): Codec => buildCodecForObject() .property("name", codecForConstString("taler-merchant")) .property("currency", codecForString()) .property("version", codecForString()) .property("currencies", codecForMap(codecForCurrencySpecificiation())) .property("exchanges", codecForList(codecForExchangeConfigInfo())) .build("TalerMerchantApi.VersionResponse"); export const codecForClaimResponse = (): Codec => buildCodecForObject() .property("contract_terms", codecForContractTerms()) .property("sig", codecForString()) .build("TalerMerchantApi.ClaimResponse"); export const codecForPaymentResponse = (): Codec => buildCodecForObject() .property("pos_confirmation", codecOptional(codecForString())) .property("sig", codecForString()) .build("TalerMerchantApi.PaymentResponse"); export const codecForStatusPaid = (): Codec => buildCodecForObject() .property("refund_amount", codecForAmountString()) .property("refund_pending", codecForBoolean()) .property("refund_taken", codecForAmountString()) .property("refunded", codecForBoolean()) .property("type", codecForConstString("paid")) .build("TalerMerchantApi.StatusPaid"); export const codecForStatusGoto = (): Codec => buildCodecForObject() .property("public_reorder_url", codecForURL()) .property("type", codecForConstString("goto")) .build("TalerMerchantApi.StatusGotoResponse"); export const codecForStatusStatusUnpaid = (): Codec => buildCodecForObject() .property("type", codecForConstString("unpaid")) .property("already_paid_order_id", codecOptional(codecForString())) .property("fulfillment_url", codecOptional(codecForString())) .property("taler_pay_uri", codecForTalerUriString()) .build("TalerMerchantApi.PaymentResponse"); export const codecForPaidRefundStatusResponse = (): Codec => buildCodecForObject() .property("pos_confirmation", codecOptional(codecForString())) .property("refunded", codecForBoolean()) .build("TalerMerchantApi.PaidRefundStatusResponse"); export const codecForMerchantAbortPayRefundSuccessStatus = (): Codec => buildCodecForObject() .property("exchange_pub", codecForString()) .property("exchange_sig", codecForString()) .property("exchange_status", codecForConstNumber(200)) .property("type", codecForConstString("success")) .build("TalerMerchantApi.MerchantAbortPayRefundSuccessStatus"); export const codecForMerchantAbortPayRefundFailureStatus = (): Codec => buildCodecForObject() .property("exchange_code", codecForNumber()) .property("exchange_reply", codecForAny()) .property("exchange_status", codecForNumber()) .property("type", codecForConstString("failure")) .build("TalerMerchantApi.MerchantAbortPayRefundFailureStatus"); export const codecForMerchantAbortPayRefundStatus = (): Codec => buildCodecForUnion() .discriminateOn("type") .alternative("success", codecForMerchantAbortPayRefundSuccessStatus()) .alternative("failure", codecForMerchantAbortPayRefundFailureStatus()) .build("TalerMerchantApi.MerchantAbortPayRefundStatus"); export const codecForAbortResponse = (): Codec => buildCodecForObject() .property("refunds", codecForList(codecForMerchantAbortPayRefundStatus())) .build("TalerMerchantApi.AbortResponse"); export const codecForWalletRefundResponse = (): Codec => buildCodecForObject() .property("merchant_pub", codecForString()) .property("refund_amount", codecForAmountString()) .property("refunds", codecForList(codecForMerchantCoinRefundStatus())) .build("TalerMerchantApi.AbortResponse"); export const codecForMerchantCoinRefundSuccessStatus = (): Codec => buildCodecForObject() .property("type", codecForConstString("success")) .property("coin_pub", codecForString()) .property("exchange_status", codecForConstNumber(200)) .property("exchange_sig", codecForString()) .property("rtransaction_id", codecForNumber()) .property("refund_amount", codecForAmountString()) .property("exchange_pub", codecForString()) .property("execution_time", codecForTimestamp) .build("TalerMerchantApi.MerchantCoinRefundSuccessStatus"); export const codecForMerchantCoinRefundFailureStatus = (): Codec => buildCodecForObject() .property("type", codecForConstString("failure")) .property("coin_pub", codecForString()) .property("exchange_status", codecForNumber()) .property("rtransaction_id", codecForNumber()) .property("refund_amount", codecForAmountString()) .property("exchange_code", codecOptional(codecForNumber())) .property("exchange_reply", codecOptional(codecForAny())) .property("execution_time", codecForTimestamp) .build("TalerMerchantApi.MerchantCoinRefundFailureStatus"); export const codecForMerchantCoinRefundStatus = (): Codec => buildCodecForUnion() .discriminateOn("type") .alternative("success", codecForMerchantCoinRefundSuccessStatus()) .alternative("failure", codecForMerchantCoinRefundFailureStatus()) .build("TalerMerchantApi.MerchantCoinRefundStatus"); export const codecForQueryInstancesResponse = (): Codec => buildCodecForObject() .property("name", codecForString()) .property("user_type", codecForString()) .property("email", codecOptional(codecForString())) .property("website", codecOptional(codecForString())) .property("logo", codecOptional(codecForString())) .property("merchant_pub", codecForString()) .property("address", codecForLocation()) .property("jurisdiction", codecForLocation()) .property("use_stefan", codecForBoolean()) .property("default_wire_transfer_delay", codecForDuration) .property("default_pay_delay", codecForDuration) .property( "auth", buildCodecForObject<{ method: "external" | "token"; }>() .property( "method", codecForEither( codecForConstString("token"), codecForConstString("external"), ), ) .build("TalerMerchantApi.QueryInstancesResponse.auth"), ) .build("TalerMerchantApi.QueryInstancesResponse"); export const codecForAccountKycRedirects = (): Codec => buildCodecForObject() .property( "pending_kycs", codecForList(codecForMerchantAccountKycRedirect()), ) .property("timeout_kycs", codecForList(codecForExchangeKycTimeout())) .build("TalerMerchantApi.AccountKycRedirects"); export const codecForMerchantAccountKycRedirect = (): Codec => buildCodecForObject() .property("kyc_url", codecForURL()) .property("aml_status", codecForNumber()) .property("exchange_url", codecForURL()) .property("payto_uri", codecForPaytoString()) .build("TalerMerchantApi.MerchantAccountKycRedirect"); export const codecForExchangeKycTimeout = (): Codec => buildCodecForObject() .property("exchange_url", codecForURL()) .property("exchange_code", codecForNumber()) .property("exchange_http_status", codecForNumber()) .build("TalerMerchantApi.ExchangeKycTimeout"); export const codecForAccountAddResponse = (): Codec => buildCodecForObject() .property("h_wire", codecForString()) .property("salt", codecForString()) .build("TalerMerchantApi.AccountAddResponse"); export const codecForAccountsSummaryResponse = (): Codec => buildCodecForObject() .property("accounts", codecForList(codecForBankAccountSummaryEntry())) .build("TalerMerchantApi.AccountsSummaryResponse"); export const codecForBankAccountSummaryEntry = (): Codec => buildCodecForObject() .property("payto_uri", codecForPaytoString()) .property("h_wire", codecForString()) .build("TalerMerchantApi.BankAccountSummaryEntry"); export const codecForBankAccountEntry = (): Codec => buildCodecForObject() .property("payto_uri", codecForPaytoString()) .property("h_wire", codecForString()) .property("salt", codecForString()) .property("credit_facade_url", codecOptional(codecForURL())) .property("active", codecOptional(codecForBoolean())) .build("TalerMerchantApi.BankAccountEntry"); export const codecForInventorySummaryResponse = (): Codec => buildCodecForObject() .property("products", codecForList(codecForInventoryEntry())) .build("TalerMerchantApi.InventorySummaryResponse"); export const codecForInventoryEntry = (): Codec => buildCodecForObject() .property("product_id", codecForString()) .property("product_serial", codecForNumber()) .build("TalerMerchantApi.InventoryEntry"); export const codecForProductDetail = (): Codec => buildCodecForObject() .property("description", codecForString()) .property("description_i18n", codecForInternationalizedString()) .property("unit", codecForString()) .property("price", codecForAmountString()) .property("image", codecForString()) .property("taxes", codecForList(codecForTax())) .property("address", codecForLocation()) .property("next_restock", codecForTimestamp) .property("total_stock", codecForNumber()) .property("total_sold", codecForNumber()) .property("total_lost", codecForNumber()) .property("minimum_age", codecOptional(codecForNumber())) .build("TalerMerchantApi.ProductDetail"); export const codecForTax = (): Codec => buildCodecForObject() .property("name", codecForString()) .property("tax", codecForAmountString()) .build("TalerMerchantApi.Tax"); export const codecForPostOrderResponse = (): Codec => buildCodecForObject() .property("order_id", codecForString()) .property("token", codecOptional(codecForString())) .build("TalerMerchantApi.PostOrderResponse"); export const codecForOutOfStockResponse = (): Codec => buildCodecForObject() .property("product_id", codecForString()) .property("available_quantity", codecForNumber()) .property("requested_quantity", codecForNumber()) .property("restock_expected", codecForTimestamp) .build("TalerMerchantApi.OutOfStockResponse"); export const codecForOrderHistory = (): Codec => buildCodecForObject() .property("orders", codecForList(codecForOrderHistoryEntry())) .build("TalerMerchantApi.OrderHistory"); export const codecForOrderHistoryEntry = (): Codec => buildCodecForObject() .property("order_id", codecForString()) .property("row_id", codecForNumber()) .property("timestamp", codecForTimestamp) .property("amount", codecForAmountString()) .property("summary", codecForString()) .property("refundable", codecForBoolean()) .property("paid", codecForBoolean()) .build("TalerMerchantApi.OrderHistoryEntry"); export const codecForMerchant = (): Codec => buildCodecForObject() .property("name", codecForString()) .property("email", codecOptional(codecForString())) .property("logo", codecOptional(codecForString())) .property("website", codecOptional(codecForString())) .property("address", codecOptional(codecForLocation())) .property("jurisdiction", codecOptional(codecForLocation())) .build("TalerMerchantApi.MerchantInfo"); export const codecForExchange = (): Codec => buildCodecForObject() .property("master_pub", codecForString()) .property("priority", codecForNumber()) .property("url", codecForString()) .build("TalerMerchantApi.Exchange"); export const codecForContractTerms = (): Codec => buildCodecForObject() .property("order_id", codecForString()) .property("fulfillment_url", codecOptional(codecForString())) .property("fulfillment_message", codecOptional(codecForString())) .property( "fulfillment_message_i18n", codecOptional(codecForInternationalizedString()), ) .property("merchant_base_url", codecForString()) .property("h_wire", codecForString()) .property("auto_refund", codecOptional(codecForDuration)) .property("wire_method", codecForString()) .property("summary", codecForString()) .property( "summary_i18n", codecOptional(codecForInternationalizedString()), ) .property("nonce", codecForString()) .property("amount", codecForAmountString()) .property("pay_deadline", codecForTimestamp) .property("refund_deadline", codecForTimestamp) .property("wire_transfer_deadline", codecForTimestamp) .property("timestamp", codecForTimestamp) .property("delivery_location", codecOptional(codecForLocation())) .property("delivery_date", codecOptional(codecForTimestamp)) .property("max_fee", codecForAmountString()) .property("merchant", codecForMerchant()) .property("merchant_pub", codecForString()) .property("exchanges", codecForList(codecForExchange())) .property("products", codecForList(codecForProduct())) .property("extra", codecForAny()) .build("TalerMerchantApi.ContractTerms"); export const codecForProduct = (): Codec => buildCodecForObject() .property("product_id", codecOptional(codecForString())) .property("description", codecForString()) .property( "description_i18n", codecOptional(codecForInternationalizedString()), ) .property("quantity", codecOptional(codecForNumber())) .property("unit", codecOptional(codecForString())) .property("price", codecOptional(codecForAmountString())) .property("image", codecOptional(codecForString())) .property("taxes", codecOptional(codecForList(codecForTax()))) .property("delivery_date", codecOptional(codecForTimestamp)) .build("TalerMerchantApi.Product"); export const codecForCheckPaymentPaidResponse = (): Codec => buildCodecForObject() .property("order_status", codecForConstString("paid")) .property("refunded", codecForBoolean()) .property("refund_pending", codecForBoolean()) .property("wired", codecForBoolean()) .property("deposit_total", codecForAmountString()) .property("exchange_code", codecForNumber()) .property("exchange_http_status", codecForNumber()) .property("refund_amount", codecForAmountString()) .property("contract_terms", codecForContractTerms()) .property("wire_reports", codecForList(codecForTransactionWireReport())) .property("wire_details", codecForList(codecForTransactionWireTransfer())) .property("refund_details", codecForList(codecForRefundDetails())) .property("order_status_url", codecForURL()) .build("TalerMerchantApi.CheckPaymentPaidResponse"); export const codecForCheckPaymentUnpaidResponse = (): Codec => buildCodecForObject() .property("order_status", codecForConstString("unpaid")) .property("taler_pay_uri", codecForTalerUriString()) .property("creation_time", codecForTimestamp) .property("summary", codecForString()) .property("total_amount", codecForAmountString()) .property("already_paid_order_id", codecOptional(codecForString())) .property("already_paid_fulfillment_url", codecOptional(codecForString())) .property("order_status_url", codecForString()) .build("TalerMerchantApi.CheckPaymentPaidResponse"); export const codecForCheckPaymentClaimedResponse = (): Codec => buildCodecForObject() .property("order_status", codecForConstString("claimed")) .property("contract_terms", codecForContractTerms()) .build("TalerMerchantApi.CheckPaymentClaimedResponse"); export const codecForMerchantOrderPrivateStatusResponse = (): Codec => buildCodecForUnion() .discriminateOn("order_status") .alternative("paid", codecForCheckPaymentPaidResponse()) .alternative("unpaid", codecForCheckPaymentUnpaidResponse()) .alternative("claimed", codecForCheckPaymentClaimedResponse()) .build("TalerMerchantApi.MerchantOrderStatusResponse"); export const codecForRefundDetails = (): Codec => buildCodecForObject() .property("reason", codecForString()) .property("pending", codecForBoolean()) .property("timestamp", codecForTimestamp) .property("amount", codecForAmountString()) .build("TalerMerchantApi.RefundDetails"); export const codecForTransactionWireTransfer = (): Codec => buildCodecForObject() .property("exchange_url", codecForURL()) .property("wtid", codecForString()) .property("execution_time", codecForTimestamp) .property("amount", codecForAmountString()) .property("confirmed", codecForBoolean()) .build("TalerMerchantApi.TransactionWireTransfer"); export const codecForTransactionWireReport = (): Codec => buildCodecForObject() .property("code", codecForNumber()) .property("hint", codecForString()) .property("exchange_code", codecForNumber()) .property("exchange_http_status", codecForNumber()) .property("coin_pub", codecForString()) .build("TalerMerchantApi.TransactionWireReport"); export const codecForMerchantRefundResponse = (): Codec => buildCodecForObject() .property("taler_refund_uri", codecForTalerUriString()) .property("h_contract", codecForString()) .build("TalerMerchantApi.MerchantRefundResponse"); export const codecForTansferList = (): Codec => buildCodecForObject() .property("transfers", codecForList(codecForTransferDetails())) .build("TalerMerchantApi.TransferList"); export const codecForTransferDetails = (): Codec => buildCodecForObject() .property("credit_amount", codecForAmountString()) .property("wtid", codecForString()) .property("payto_uri", codecForPaytoString()) .property("exchange_url", codecForURL()) .property("transfer_serial_id", codecForNumber()) .property("execution_time", codecOptional(codecForTimestamp)) .property("verified", codecOptional(codecForBoolean())) .property("confirmed", codecOptional(codecForBoolean())) .build("TalerMerchantApi.TransferDetails"); export const codecForOtpDeviceSummaryResponse = (): Codec => buildCodecForObject() .property("otp_devices", codecForList(codecForOtpDeviceEntry())) .build("TalerMerchantApi.OtpDeviceSummaryResponse"); export const codecForOtpDeviceEntry = (): Codec => buildCodecForObject() .property("otp_device_id", codecForString()) .property("device_description", codecForString()) .build("TalerMerchantApi.OtpDeviceEntry"); export const codecForOtpDeviceDetails = (): Codec => buildCodecForObject() .property("device_description", codecForString()) .property("otp_algorithm", codecForNumber()) .property("otp_ctr", codecOptional(codecForNumber())) .property("otp_timestamp", codecForNumber()) .property("otp_code", codecOptional(codecForString())) .build("TalerMerchantApi.OtpDeviceDetails"); export const codecForTemplateSummaryResponse = (): Codec => buildCodecForObject() .property("templates", codecForList(codecForTemplateEntry())) .build("TalerMerchantApi.TemplateSummaryResponse"); export const codecForTemplateEntry = (): Codec => buildCodecForObject() .property("template_id", codecForString()) .property("template_description", codecForString()) .build("TalerMerchantApi.TemplateEntry"); export const codecForTemplateDetails = (): Codec => buildCodecForObject() .property("template_description", codecForString()) .property("otp_id", codecOptional(codecForString())) .property("template_contract", codecForTemplateContractDetails()) .property("required_currency", codecOptional(codecForString())) .property( "editable_defaults", codecOptional(codecForTemplateContractDetailsDefaults()), ) .build("TalerMerchantApi.TemplateDetails"); export const codecForTemplateContractDetails = (): Codec => buildCodecForObject() .property("summary", codecOptional(codecForString())) .property("currency", codecOptional(codecForString())) .property("amount", codecOptional(codecForAmountString())) .property("minimum_age", codecForNumber()) .property("pay_duration", codecForDuration) .build("TalerMerchantApi.TemplateContractDetails"); export const codecForTemplateContractDetailsDefaults = (): Codec => buildCodecForObject() .property("summary", codecOptional(codecForString())) .property("currency", codecOptional(codecForString())) .property("amount", codecOptional(codecForAmountString())) .property("minimum_age", codecOptional(codecForNumber())) .property("pay_duration", codecOptional(codecForDuration)) .build("TalerMerchantApi.TemplateContractDetailsDefaults"); export const codecForWalletTemplateDetails = (): Codec => buildCodecForObject() .property("template_contract", codecForTemplateContractDetails()) .property("required_currency", codecOptional(codecForString())) .property( "editable_defaults", codecOptional(codecForTemplateContractDetailsDefaults()), ) .build("TalerMerchantApi.WalletTemplateDetails"); export const codecForWebhookSummaryResponse = (): Codec => buildCodecForObject() .property("webhooks", codecForList(codecForWebhookEntry())) .build("TalerMerchantApi.WebhookSummaryResponse"); export const codecForWebhookEntry = (): Codec => buildCodecForObject() .property("webhook_id", codecForString()) .property("event_type", codecForString()) .build("TalerMerchantApi.WebhookEntry"); export const codecForWebhookDetails = (): Codec => buildCodecForObject() .property("event_type", codecForString()) .property("url", codecForString()) .property("http_method", codecForString()) .property("header_template", codecOptional(codecForString())) .property("body_template", codecOptional(codecForString())) .build("TalerMerchantApi.WebhookDetails"); export const codecForTokenFamilyKind = (): Codec => codecForEither( codecForConstString("discount"), codecForConstString("subscription"), ) as any; //FIXME: create a codecForEnum export const codecForTokenFamilyDetails = (): Codec => buildCodecForObject() .property("slug", codecForString()) .property("name", codecForString()) .property("description", codecForString()) .property("description_i18n", codecForInternationalizedString()) .property("valid_after", codecForTimestamp) .property("valid_before", codecForTimestamp) .property("duration", codecForDuration) .property("kind", codecForTokenFamilyKind()) .property("issued", codecForNumber()) .property("redeemed", codecForNumber()) .build("TalerMerchantApi.TokenFamilyDetails"); export const codecForTokenFamiliesList = (): Codec => buildCodecForObject() .property("token_families", codecForList(codecForTokenFamilySummary())) .build("TalerMerchantApi.TokenFamiliesList"); export const codecForTokenFamilySummary = (): Codec => buildCodecForObject() .property("slug", codecForString()) .property("name", codecForString()) .property("valid_after", codecForTimestamp) .property("valid_before", codecForTimestamp) .property("kind", codecForTokenFamilyKind()) .build("TalerMerchantApi.TokenFamilySummary"); export const codecForInstancesResponse = (): Codec => buildCodecForObject() .property("instances", codecForList(codecForInstance())) .build("TalerMerchantApi.InstancesResponse"); export const codecForInstance = (): Codec => buildCodecForObject() .property("name", codecForString()) .property("user_type", codecForString()) .property("website", codecOptional(codecForString())) .property("logo", codecOptional(codecForString())) .property("id", codecForString()) .property("merchant_pub", codecForString()) .property("payment_targets", codecForList(codecForString())) .property("deleted", codecForBoolean()) .build("TalerMerchantApi.Instance"); export const codecForExchangeConfig = (): Codec => buildCodecForObject() .property("version", codecForString()) .property("name", codecForConstString("taler-exchange")) .property("implementation", codecOptional(codecForURN())) .property("currency", codecForString()) .property("currency_specification", codecForCurrencySpecificiation()) .property("supported_kyc_requirements", codecForList(codecForString())) .build("TalerExchangeApi.ExchangeVersionResponse"); export const codecForExchangeKeys = (): Codec => buildCodecForObject() .property("version", codecForString()) .property("base_url", codecForString()) .property("currency", codecForString()) .build("TalerExchangeApi.ExchangeKeysResponse"); const codecForBalance = (): Codec => buildCodecForObject() .property("amount", codecForAmountString()) .property( "credit_debit_indicator", codecForEither( codecForConstString("credit"), codecForConstString("debit"), ), ) .build("TalerCorebankApi.Balance"); const codecForPublicAccount = (): Codec => buildCodecForObject() .property("username", codecForString()) .property("balance", codecForBalance()) .property("payto_uri", codecForPaytoString()) .property("is_taler_exchange", codecForBoolean()) .property("row_id", codecOptional(codecForNumber())) .build("TalerCorebankApi.PublicAccount"); export const codecForPublicAccountsResponse = (): Codec => buildCodecForObject() .property("public_accounts", codecForList(codecForPublicAccount())) .build("TalerCorebankApi.PublicAccountsResponse"); export const codecForAccountMinimalData = (): Codec => buildCodecForObject() .property("username", codecForString()) .property("name", codecForString()) .property("payto_uri", codecForPaytoString()) .property("balance", codecForBalance()) .property("debit_threshold", codecForAmountString()) .property("is_public", codecForBoolean()) .property("is_taler_exchange", codecForBoolean()) .property("row_id", codecOptional(codecForNumber())) .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())) .property("is_public", codecForBoolean()) .property("is_taler_exchange", codecForBoolean()) .property( "tan_channel", codecOptional( codecForEither( codecForConstString(TalerCorebankApi.TanChannel.SMS), codecForConstString(TalerCorebankApi.TanChannel.EMAIL), ), ), ) .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( "status", codecForEither( codecForConstString("pending"), codecForConstString("selected"), codecForConstString("aborted"), codecForConstString("confirmed"), ), ) .property("amount", codecForAmountString()) .property("username", codecForString()) .property("selected_reserve_pub", codecOptional(codecForString())) .property( "selected_exchange_account", codecOptional(codecForPaytoString()), ) .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", codecForTalerUriString()) .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()) .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()) .build("TalerCorebankApi.GlobalCashoutInfo"); export const codecForCashoutStatusResponse = (): Codec => buildCodecForObject() .property("amount_debit", codecForAmountString()) .property("amount_credit", codecForAmountString()) .property("subject", codecForString()) .property("creation_time", codecForTimestamp) .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("selected"), codecForConstString("aborted"), codecForConstString("confirmed"), ), ) .property("confirm_transfer_url", codecOptional(codecForURL())) .build("TalerBankIntegrationApi.BankWithdrawalOperationPostResponse"); export const codecForRevenueConfig = (): Codec => buildCodecForObject() .property("name", codecForConstString("taler-revenue")) .property("version", codecForString()) .property("currency", codecForString()) .property("implementation", codecOptional(codecForString())) .build("TalerRevenueApi.RevenueConfig"); export const codecForRevenueIncomingHistory = (): Codec => buildCodecForObject() .property("credit_account", codecForPaytoString()) .property( "incoming_transactions", codecForList(codecForRevenueIncomingBankTransaction()), ) .build("TalerRevenueApi.MerchantIncomingHistory"); export const codecForRevenueIncomingBankTransaction = (): Codec => buildCodecForObject() .property("amount", codecForAmountString()) .property("date", codecForTimestamp) .property("debit_account", codecForPaytoString()) .property("row_id", codecForNumber()) .property("subject", codecForString()) .build("TalerRevenueApi.RevenueIncomingBankTransaction"); 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"); export const codecForChallenge = (): Codec => buildCodecForObject() .property("challenge_id", codecForNumber()) .build("TalerCorebankApi.Challenge"); export const codecForTanTransmission = (): Codec => buildCodecForObject() .property( "tan_channel", codecForEither( codecForConstString(TalerCorebankApi.TanChannel.SMS), codecForConstString(TalerCorebankApi.TanChannel.EMAIL), ), ) .property("tan_info", codecForString()) .build("TalerCorebankApi.TanTransmission"); 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"); 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", codecForConversionInfo()) .build("ConversionBankConfig.IntegrationConfig"); export const codecForChallengerTermsOfServiceResponse = (): Codec => buildCodecForObject() .property("name", codecForConstString("challenger")) .property("version", codecForString()) .property("implementation", codecOptional(codecForString())) .build("ChallengerApi.ChallengerTermsOfServiceResponse"); export const codecForChallengeSetupResponse = (): Codec => buildCodecForObject() .property("nonce", codecForString()) .build("ChallengerApi.ChallengeSetupResponse"); export const codecForChallengeStatus = (): Codec => buildCodecForObject() .property("restrictions", codecForAny()) .property("fix_address", codecForBoolean()) .property("last_address", codecForAny()) .property("changes_left", codecForNumber()) .build("ChallengerApi.ChallengeStatus"); export const codecForChallengeCreateResponse = (): Codec => buildCodecForObject() .property("attempts_left", codecForNumber()) .property("address", codecForAny()) .property("transmitted", codecForBoolean()) .property("next_tx_time", codecForString()) .build("ChallengerApi.ChallengeCreateResponse"); export const codecForInvalidPinResponse = (): Codec => buildCodecForObject() .property("ec", codecForNumber()) .property("hint", codecForAny()) .property("addresses_left", codecForNumber()) .property("pin_transmissions_left", codecForNumber()) .property("auth_attempts_left", codecForNumber()) .property("exhausted", codecForBoolean()) .property("no_challenge", codecForBoolean()) .build("ChallengerApi.InvalidPinResponse"); export const codecForChallengerAuthResponse = (): Codec => buildCodecForObject() .property("access_token", codecForString()) .property("token_type", codecForAny()) .property("expires_in", codecForNumber()) .build("ChallengerApi.ChallengerAuthResponse"); export const codecForChallengerInfoResponse = (): Codec => buildCodecForObject() .property("id", codecForNumber()) .property("address", codecForAny()) .property("address_type", codecForString()) .property("expires", codecForTimestamp) .build("ChallengerApi.ChallengerInfoResponse"); 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; type Float = number; type LibtoolVersion = 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; //FIXME: implement this codec const codecForURL = codecForString; //FIXME: implement this codec const codecForLibtoolVersion = codecForString; //FIXME: implement this codec const codecForCurrencyName = codecForString; //FIXME: implement this codec const codecForDecimalNumber = codecForString; 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 RevenueConfig { // Name of the API. name: "taler-revenue"; // 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 gateway. currency: string; // URN of the implementation (needed to interpret 'revision' in version). // @since v0, may become mandatory in the future. implementation?: string; } export interface RevenueIncomingHistory { // Array of incoming transactions. incoming_transactions: RevenueIncomingBankTransaction[]; // Payto URI to identify the receiver of funds. // Credit account is shared by all incoming transactions // as per the nature of the request. credit_account: string; } export interface RevenueIncomingBankTransaction { // 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: string; // The wire transfer subject. subject: string; } } 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; // Bank display name to be used in user interfaces. // For consistency use "Taler Bank" if missing. // @since v4, will become mandatory in the next version. bank_name: 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; // If 'true' account can delete themselves // If 'false' only the admin can delete accounts allow_deletions: boolean; // If 'true' anyone can edit their name // If 'false' only admin can allow_edit_name: boolean; // If 'true' anyone can edit their cashout account // If 'false' only the admin allow_edit_cashout_payto_uri: boolean; // Default debt limit for newly created accounts default_debit_threshold: AmountString; // Currency used by this bank. currency: string; // How the bank SPA should render this currency. currency_specification: CurrencySpecification; // TAN channels supported by the server supported_tan_channels: TanChannel[]; // Wire transfer type supported by the bank. // Default to 'iban' is missing // @since v4, may become mandatory in the future. wire_type: string; } 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: TalerUriString; } 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; // Nonce to make the request idempotent. Requests with the same // request_uid that differ in any of the other fields // are rejected. // @since v4, will become mandatory in the next version. request_uid?: ShortHashCode; } 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. 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. payto_uri?: PaytoString; // If present, set the max debit allowed for this user // Only admin can set this property. debit_threshold?: AmountString; // If present, enables 2FA and set the TAN channel used for challenges // Only admin can set this property, other user can reconfig their account // after creation. tan_channel?: TanChannel; } 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. // Only admin can change this property. contact_data?: ChallengeContactData; // 'payto' URI 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. // Only admin can change this property if not allowed in config cashout_payto_uri?: PaytoString; // If present, change the legal name associated with $username. // Only admin can change this property if not allowed in config name?: string; // Make this account visible to anyone? is_public?: boolean; // If present, change the max debit allowed for this user // Only admin can change this property. debit_threshold?: AmountString; //FIX: missing in SPEC // If present, enables 2FA and set the TAN channel used for challenges tan_channel?: TanChannel | null; } export interface AccountPasswordChange { // New password. new_password: string; // Old password. If present, check that the old password matches. // Optional for admin account. old_password?: string; } export interface PublicAccountsResponse { public_accounts: PublicAccount[]; } export interface PublicAccount { // Username of the account username: string; // Internal payto URI of this bank account. payto_uri: string; // Current balance of the account balance: Balance; // Is this a taler exchange account? is_taler_exchange: boolean; // Opaque unique ID used for pagination. // @since v4, will become mandatory in the future. row_id?: Integer; } 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; // Internal payto URI of this bank account. payto_uri: PaytoString; // current balance of the account balance: Balance; // Number indicating the max debit allowed for the requesting user. debit_threshold: AmountString; // Is this account visible to anyone? is_public: boolean; // Is this a taler exchange account? is_taler_exchange: boolean; // Opaque unique ID used for pagination. // @since v4, will become mandatory in the future. row_id?: Integer; } 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; // Is this account visible to anyone? is_public: boolean; // Is this a taler exchange account? is_taler_exchange: boolean; // Is 2FA enabled and what channel is used for challenges? tan_channel?: TanChannel; } 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; } export interface CashoutResponse { // ID identifying the operation being created cashout_id: number; } /** * @deprecated since 4, use 2fa */ 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; /** * @deprecated since 4, use new 2fa */ 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; } export interface CashoutStatusResponse { // 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; // Time when the cashout was created. creation_time: Timestamp; } 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 interface TanTransmission { // Channel of the last successful transmission of the TAN challenge. tan_channel: TanChannel; // Info of the last successful transmission of the TAN challenge. tan_info: string; } export interface Challenge { // Unique identifier of the challenge to solve to run this protected // operation. challenge_id: number; } export interface ChallengeSolve { // The TAN code that solves $CHALLENGE_ID tan: string; } export enum TanChannel { SMS = "sms", EMAIL = "email", } } 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"; // URN of the implementation (needed to interpret 'revision' in version). // @since v18, may become mandatory in the future. implementation?: string; // Currency supported by this exchange, given // as a currency code ("USD" or "EUR"). 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 interface ExchangeKeysResponse { // 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; // The exchange's base URL. base_url: string; // The exchange's currency or asset unit. currency: string; /** * FIXME: PARTIALLY IMPLEMENTED!! */ // How wallets should render this currency. // currency_specification: CurrencySpecification; // // Absolute cost offset for the STEFAN curve used // // to (over) approximate fees payable by amount. // stefan_abs: AmountString; // // Factor to multiply the logarithm of the amount // // with to (over) approximate fees payable by amount. // // Note that the total to be paid is first to be // // divided by the smallest denomination to obtain // // the value that the logarithm is to be taken of. // stefan_log: AmountString; // // Linear cost factor for the STEFAN curve used // // to (over) approximate fees payable by amount. // // // // Note that this is a scalar, as it is multiplied // // with the actual amount. // stefan_lin: Float; // // Type of the asset. "fiat", "crypto", "regional" // // or "stock". Wallets should adjust their UI/UX // // based on this value. // asset_type: string; // // Array of wire accounts operated by the exchange for // // incoming wire transfers. // accounts: WireAccount[]; // // Object mapping names of wire methods (i.e. "iban" or "x-taler-bank") // // to wire fees. // wire_fees: { method: AggregateTransferFee[] }; // // List of exchanges that this exchange is partnering // // with to enable wallet-to-wallet transfers. // wads: ExchangePartner[]; // // Set to true if this exchange allows the use // // of reserves for rewards. // // @deprecated in protocol v18. // rewards_allowed: false; // // EdDSA master public key of the exchange, used to sign entries // // in denoms and signkeys. // master_public_key: EddsaPublicKey; // // Relative duration until inactive reserves are closed; // // not signed (!), can change without notice. // reserve_closing_delay: RelativeTime; // // Threshold amounts beyond which wallet should // // trigger the KYC process of the issuing // // exchange. Optional option, if not given there is no limit. // // Currency must match currency. // wallet_balance_limit_without_kyc?: AmountString[]; // // Denominations offered by this exchange // denominations: DenomGroup[]; // // Compact EdDSA signature (binary-only) over the // // contatentation of all of the master_sigs (in reverse // // chronological order by group) in the arrays under // // "denominations". Signature of TALER_ExchangeKeySetPS // 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 signkeys. It is given // // explicitly as the client might otherwise be confused by clock skew as to // // which signing key was used for the exchange_sig. // exchange_pub: EddsaPublicKey; // // Denominations for which the exchange currently offers/requests recoup. // recoup: Recoup[]; // // Array of globally applicable fees by time range. // global_fees: GlobalFees[]; // // The date when the denomination keys were last updated. // list_issue_date: Timestamp; // // Auditors of the exchange. // auditors: AuditorKeys[]; // // The exchange's signing keys. // signkeys: SignKey[]; // // Optional field with a dictionary of (name, object) pairs defining the // // supported and enabled extensions, such as age_restriction. // extensions?: { name: ExtensionManifest }; // // Signature by the exchange master key of the SHA-256 hash of the // // normalized JSON-object of field extensions, if it was set. // // The signature has purpose TALER_SIGNATURE_MASTER_EXTENSIONS. // extensions_sig?: EddsaSignature; } interface ExtensionManifest { // The criticality of the extension MUST be provided. It has the same // semantics as "critical" has for extensions in X.509: // - if "true", the client must "understand" the extension before // proceeding, // - if "false", clients can safely skip extensions they do not // understand. // (see https://datatracker.ietf.org/doc/html/rfc5280#section-4.2) critical: boolean; // The version information MUST be provided in Taler's protocol version // ranges notation, see // https://docs.taler.net/core/api-common.html#protocol-version-ranges version: LibtoolVersion; // Optional configuration object, defined by the feature itself config?: object; } interface SignKey { // The actual exchange's EdDSA signing public key. key: EddsaPublicKey; // Initial validity date for the signing key. stamp_start: Timestamp; // Date when the exchange will stop using the signing key, allowed to overlap // slightly with the next signing key's validity to allow for clock skew. stamp_expire: Timestamp; // Date when all signatures made by the signing key expire and should // henceforth no longer be considered valid in legal disputes. stamp_end: Timestamp; // Signature over key and stamp_expire by the exchange master key. // Signature of TALER_ExchangeSigningKeyValidityPS. // Must have purpose TALER_SIGNATURE_MASTER_SIGNING_KEY_VALIDITY. master_sig: EddsaSignature; } interface AuditorKeys { // The auditor's EdDSA signing public key. auditor_pub: EddsaPublicKey; // The auditor's URL. auditor_url: string; // The auditor's name (for humans). auditor_name: string; // An array of denomination keys the auditor affirms with its signature. // Note that the message only includes the hash of the public key, while the // signature is actually over the expanded information including expiration // times and fees. The exact format is described below. denomination_keys: AuditorDenominationKey[]; } interface AuditorDenominationKey { // Hash of the public RSA key used to sign coins of the respective // denomination. Note that the auditor's signature covers more than just // the hash, but this other information is already provided in denoms and // thus not repeated here. denom_pub_h: HashCode; // Signature of TALER_ExchangeKeyValidityPS. auditor_sig: EddsaSignature; } interface GlobalFees { // What date (inclusive) does these fees go into effect? start_date: Timestamp; // What date (exclusive) does this fees stop going into effect? end_date: Timestamp; // Account history fee, charged when a user wants to // obtain a reserve/account history. history_fee: AmountString; // Annual fee charged for having an open account at the // exchange. Charged to the account. If the account // balance is insufficient to cover this fee, the account // is automatically deleted/closed. (Note that the exchange // will keep the account history around for longer for // regulatory reasons.) account_fee: AmountString; // Purse fee, charged only if a purse is abandoned // and was not covered by the account limit. purse_fee: AmountString; // How long will the exchange preserve the account history? // After an account was deleted/closed, the exchange will // retain the account history for legal reasons until this time. history_expiration: RelativeTime; // Non-negative number of concurrent purses that any // account holder is allowed to create without having // to pay the purse_fee. purse_account_limit: Integer; // How long does an exchange keep a purse around after a purse // has expired (or been successfully merged)? A 'GET' request // for a purse will succeed until the purse expiration time // plus this value. purse_timeout: RelativeTime; // Signature of TALER_GlobalFeesPS. master_sig: EddsaSignature; } interface Recoup { // Hash of the public key of the denomination that is being revoked under // emergency protocol (see /recoup). h_denom_pub: HashCode; // We do not include any signature here, as the primary use-case for // this emergency involves the exchange having lost its signing keys, // so such a signature here would be pretty worthless. However, the // exchange will not honor /recoup requests unless they are for // denomination keys listed here. } interface AggregateTransferFee { // Per transfer wire transfer fee. wire_fee: AmountString; // Per transfer closing fee. closing_fee: AmountString; // What date (inclusive) does this fee go into effect? // The different fees must cover the full time period in which // any of the denomination keys are valid without overlap. start_date: Timestamp; // What date (exclusive) does this fee stop going into effect? // The different fees must cover the full time period in which // any of the denomination keys are valid without overlap. end_date: Timestamp; // Signature of TALER_MasterWireFeePS with // purpose TALER_SIGNATURE_MASTER_WIRE_FEES. sig: EddsaSignature; } interface ExchangePartner { // Base URL of the partner exchange. partner_base_url: string; // Public master key of the partner exchange. partner_master_pub: EddsaPublicKey; // Per exchange-to-exchange transfer (wad) fee. wad_fee: AmountString; // Exchange-to-exchange wad (wire) transfer frequency. wad_frequency: RelativeTime; // When did this partnership begin (under these conditions)? start_date: Timestamp; // How long is this partnership expected to last? end_date: Timestamp; // Signature using the exchange's offline key over // TALER_WadPartnerSignaturePS // with purpose TALER_SIGNATURE_MASTER_PARTNER_DETAILS. master_sig: EddsaSignature; } type DenomGroup = | DenomGroupRsa | DenomGroupCs | DenomGroupRsaAgeRestricted | DenomGroupCsAgeRestricted; interface DenomGroupRsa extends DenomGroupCommon { cipher: "RSA"; denoms: ({ rsa_pub: RsaPublicKey; } & DenomCommon)[]; } interface DenomGroupCs extends DenomGroupCommon { cipher: "CS"; denoms: ({ cs_pub: Cs25519Point; } & DenomCommon)[]; } // Binary representation of the age groups. // The bits set in the mask mark the edges at the beginning of a next age // group. F.e. for the age groups // 0-7, 8-9, 10-11, 12-13, 14-15, 16-17, 18-21, 21-* // the following bits are set: // // 31 24 16 8 0 // | | | | | // oooooooo oo1oo1o1 o1o1o1o1 ooooooo1 // // A value of 0 means that the exchange does not support the extension for // age-restriction. type AgeMask = Integer; interface DenomGroupRsaAgeRestricted extends DenomGroupCommon { cipher: "RSA+age_restricted"; age_mask: AgeMask; denoms: ({ rsa_pub: RsaPublicKey; } & DenomCommon)[]; } interface DenomGroupCsAgeRestricted extends DenomGroupCommon { cipher: "CS+age_restricted"; age_mask: AgeMask; denoms: ({ cs_pub: Cs25519Point; } & DenomCommon)[]; } // Common attributes for all denomination groups interface DenomGroupCommon { // How much are coins of this denomination worth? value: AmountString; // Fee charged by the exchange for withdrawing a coin of this denomination. fee_withdraw: AmountString; // Fee charged by the exchange for depositing a coin of this denomination. fee_deposit: AmountString; // Fee charged by the exchange for refreshing a coin of this denomination. fee_refresh: AmountString; // Fee charged by the exchange for refunding a coin of this denomination. fee_refund: AmountString; } interface DenomCommon { // Signature of TALER_DenominationKeyValidityPS. master_sig: EddsaSignature; // When does the denomination key become valid? stamp_start: Timestamp; // When is it no longer possible to withdraw coins // of this denomination? stamp_expire_withdraw: Timestamp; // When is it no longer possible to deposit coins // of this denomination? stamp_expire_deposit: Timestamp; // Timestamp indicating by when legal disputes relating to these coins must // be settled, as the exchange will afterwards destroy its evidence relating to // transactions involving this coin. stamp_expire_legal: Timestamp; // Set to 'true' if the exchange somehow "lost" // the private key. The denomination was not // necessarily revoked, but still cannot be used // to withdraw coins at this time (theoretically, // the private key could be recovered in the // future; coins signed with the private key // remain valid). lost?: boolean; } type DenominationKey = RsaDenominationKey | CSDenominationKey; interface RsaDenominationKey { cipher: "RSA"; // 32-bit age mask. age_mask: Integer; // RSA public key rsa_public_key: RsaPublicKey; } interface CSDenominationKey { cipher: "CS"; // 32-bit age mask. age_mask: Integer; // Public key of the denomination. cs_public_key: Cs25519Point; } } 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"; // URN of the implementation (needed to interpret 'revision' in version). // @since **v8**, may become mandatory in the future. implementation?: string; // 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 services 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. Note that the actual currency // specifications are a *hint* for applications // that would like *advice* on how to render amounts. // Applications *may* ignore the currency specification // if they know how to render currencies that they are // used with. currencies: { [currency: string]: CurrencySpecification }; // Array of exchanges trusted by the merchant. // Since protocol **v6**. exchanges: ExchangeConfigInfo[]; } export interface ExchangeConfigInfo { // Base URL of the exchange REST API. base_url: string; // Currency for which the merchant is configured // to trust the exchange. // May not be the one the exchange actually uses, // but is the only one we would trust this exchange for. currency: string; // Offline master public key of the exchange. The // /keys data must be signed with this public // key for us to trust it. master_pub: EddsaPublicKey; } 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; } export interface PaymentStatusRequestParams { // Hash of the order’s contract terms (this is used to // authenticate the wallet/customer in case // $ORDER_ID is guessable). // Required once an order was claimed. contractTermHash?: string; // Authorizes the request via the claim token that // was returned in the PostOrderResponse. Used with // unclaimed orders only. Whether token authorization is // required is determined by the merchant when the // frontend creates the order. claimToken?: string; // Session ID that the payment must be bound to. // If not specified, the payment is not session-bound. sessionId?: string; // If specified, the merchant backend will wait up to // timeout_ms milliseconds for completion of the payment // before sending the HTTP response. A client must never // rely on this behavior, as the merchant backend may return // a response immediately. timeout?: number; // If set to “yes”, poll for the order’s pending refunds // to be picked up. timeout_ms specifies how long we // will wait for the refund. awaitRefundObtained?: boolean; // Indicates that we are polling for a refund above the // given AMOUNT. timeout_ms will specify how long we // will wait for the refund. refund?: AmountString; // Since protocol v9 refunded orders are only returned // under “already_paid_order_id” if this flag is set // explicitly to “YES”. allowRefundedForRepurchase?: boolean; } export interface GetKycStatusRequestParams { // If specified, the KYC check should return // the KYC status only for this wire account. // Otherwise, for all wire accounts. wireHash?: string; // If specified, the KYC check should return // the KYC status only for the given exchange. // Otherwise, for all exchanges we interacted with. exchangeURL?: string; // If specified, the merchant will wait up to // timeout_ms milliseconds for the exchanges to // confirm completion of the KYC process(es). timeout?: number; } export interface GetOtpDeviceRequestParams { // Timestamp in seconds to use when calculating // the current OTP code of the device. Since protocol v10. faketime?: number; // Price to use when calculating the current OTP // code of the device. Since protocol v10. price?: AmountString; } export interface GetOrderRequestParams { // Session ID that the payment must be bound to. // If not specified, the payment is not session-bound. sessionId?: string; // Timeout in milliseconds to wait for a payment if // the answer would otherwise be negative (long polling). timeout?: number; // Since protocol v9 refunded orders are only returned // under “already_paid_order_id” if this flag is set // explicitly to “YES”. allowRefundedForRepurchase?: boolean; } export interface ListWireTransferRequestParams { // Filter for transfers to the given bank account // (subject and amount MUST NOT be given in the payto URI). paytoURI?: string; // Filter for transfers executed before the given timestamp. before?: number; // Filter for transfers executed after the given timestamp. after?: number; // At most return the given number of results. Negative for // descending in execution time, positive for ascending in // execution time. Default is -20. limit?: number; // Starting transfer_serial_id for an iteration. offset?: string; // Filter transfers by verification status. verified?: boolean; order?: "asc" | "dec"; } export interface ListOrdersRequestParams { // If set to yes, only return paid orders, if no only // unpaid orders. Do not give (or use “all”) to see all // orders regardless of payment status. paid?: boolean; // If set to yes, only return refunded orders, if no only // unrefunded orders. Do not give (or use “all”) to see // all orders regardless of refund status. refunded?: boolean; // If set to yes, only return wired orders, if no only // orders with missing wire transfers. Do not give (or // use “all”) to see all orders regardless of wire transfer // status. wired?: boolean; // At most return the given number of results. Negative // for descending by row ID, positive for ascending by // row ID. Default is 20. Since protocol v12. limit?: number; // Non-negative date in seconds after the UNIX Epoc, see delta // for its interpretation. If not specified, we default to the // oldest or most recent entry, depending on delta. date?: AbsoluteTime; // Starting product_serial_id for an iteration. // Since protocol v12. offset?: string; // Timeout in milliseconds to wait for additional orders if the // answer would otherwise be negative (long polling). Only useful // if delta is positive. Note that the merchant MAY still return // a response that contains fewer than delta orders. timeout?: number; // Since protocol v6. Filters by session ID. sessionId?: string; // Since protocol v6. Filters by fulfillment URL. fulfillmentUrl?: string; order?: "asc" | "dec"; } export 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; } export interface StatusPaid { type: "paid"; // 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; } export interface StatusGotoResponse { type: "goto"; // 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; } export interface StatusUnpaidResponse { type: "unpaid"; // 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; } export interface PaidRefundStatusResponse { // Text to be shown to the point-of-sale staff as a proof of // payment (present only if reusable OTP algorithm is used). pos_confirmation?: string; // True if the order has been subjected to // refunds. False if it was simply paid. refunded: boolean; } export 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; } export 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; } export 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[]; } export type MerchantAbortPayRefundStatus = | MerchantAbortPayRefundSuccessStatus | MerchantAbortPayRefundFailureStatus; // Details about why a refund failed. export 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. export 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; } export interface WalletRefundRequest { // Hash of the order's contract terms (this is used to authenticate the // wallet/customer). h_contract: HashCode; } export 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; } export type MerchantCoinRefundStatus = | MerchantCoinRefundSuccessStatus | MerchantCoinRefundFailureStatus; // Details about why a refund failed. export 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. export 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; } export 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; } export 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?: AccessToken; } export 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; } export interface InstancesResponse { // List of instances that are present in the backend (see Instance). instances: Instance[]; } export 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; } export 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: { method: "external" | "token"; }; } export interface AccountKycRedirects { // Array of pending KYCs. pending_kycs: MerchantAccountKycRedirect[]; // Array of exchanges with no reply. timeout_kycs: ExchangeKycTimeout[]; } export 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; } export 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; } export 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; } export type FacadeCredentials = | NoFacadeCredentials | BasicAuthFacadeCredentials; export interface NoFacadeCredentials { type: "none"; } export interface BasicAuthFacadeCredentials { type: "basic"; // Username to use to authenticate username: string; // Password to use to authenticate password: string; } export interface AccountAddResponse { // Hash over the wire details (including over the salt). h_wire: HashCode; // Salt used to compute h_wire. salt: HashCode; } export 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; } export interface AccountsSummaryResponse { // List of accounts that are known for the instance. accounts: BankAccountSummaryEntry[]; } // TODO: missing in docs export interface BankAccountSummaryEntry { // payto:// URI of the account. payto_uri: PaytoString; // Hash over the wire details (including over the salt). h_wire: HashCode; } export 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; } export 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; } export 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; } export interface InventorySummaryResponse { // List of products that are present in the inventory. products: InventoryEntry[]; } export interface InventoryEntry { // Product identifier, as found in the product. product_id: string; // product_serial_id of the product in the database. product_serial: Integer; } export 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; } export 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; } export 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. // When creating an order, the fulfillment URL can // contain ${ORDER_ID} which will be substituted with the // order ID of the newly created order. 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; } export 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; } export 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; } export interface OrderHistory { // Timestamp-sorted array of all orders matching the query. // The order of the sorting depends on the sign of delta. orders: OrderHistoryEntry[]; } export 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; } export type MerchantOrderStatusResponse = | CheckPaymentPaidResponse | CheckPaymentClaimedResponse | CheckPaymentUnpaidResponse; export 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; } export interface CheckPaymentClaimedResponse { // A wallet claimed the order, but did not yet pay for the contract. order_status: "claimed"; // Contract terms. contract_terms: ContractTerms; } export 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. } export 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; } export 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; } export 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; } export interface ForgetRequest { // Array of valid JSON paths to forgettable fields in the order's // contract terms. fields: string[]; } export interface RefundRequest { // Amount to be refunded. refund: AmountString; // Human-readable refund justification. reason: string; } export 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; } export 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; } export interface TransferList { // List of all the transfers that fit the filter that we know. transfers: TransferDetails[]; } export 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; } export interface OtpDeviceAddDetails { // Device ID to use. otp_device_id: string; // Human-readable description for the device. otp_device_description: string; // A key encoded with RFC 3548 Base32. // IMPORTANT: This is not using the typical // Taler base32-crockford encoding. // Instead it uses the RFC 3548 encoding to // be compatible with the TOTP standard. otp_key: string; // Algorithm for computing the POS confirmation. // "NONE" or 0: No algorithm (no pos confirmation will be generated) // "TOTP_WITHOUT_PRICE" or 1: Without amounts (typical OTP device) // "TOTP_WITH_PRICE" or 2: With amounts (special-purpose OTP device) // The "String" variants are supported @since protocol **v7**. otp_algorithm: Integer | string; // Counter for counter-based OTP devices. otp_ctr?: Integer; } export interface OtpDevicePatchDetails { // Human-readable description for the device. otp_device_description: string; // A key encoded with RFC 3548 Base32. // IMPORTANT: This is not using the typical // Taler base32-crockford encoding. // Instead it uses the RFC 3548 encoding to // be compatible with the TOTP standard. otp_key: string; // Algorithm for computing the POS confirmation. otp_algorithm: Integer; // Counter for counter-based OTP devices. otp_ctr?: Integer; } export interface OtpDeviceSummaryResponse { // Array of devices that are present in our backend. otp_devices: OtpDeviceEntry[]; } export interface OtpDeviceEntry { // Device identifier. otp_device_id: string; // Human-readable description for the device. device_description: string; } export interface OtpDeviceDetails { // Human-readable description for the device. device_description: string; // Algorithm for computing the POS confirmation. // // Currently, the following numbers are defined: // 0: None // 1: TOTP without price // 2: TOTP with price otp_algorithm: Integer; // Counter for counter-based OTP devices. otp_ctr?: Integer; // Current time for time-based OTP devices. // Will match the faketime argument of the // query if one was present, otherwise the current // time at the backend. // // Available since protocol **v10**. otp_timestamp: Integer; // Current OTP confirmation string of the device. // Matches exactly the string that would be returned // as part of a payment confirmation for the given // amount and time (so may contain multiple OTP codes). // // If the otp_algorithm is time-based, the code is // returned for the current time, or for the faketime // if a TIMESTAMP query argument was provided by the client. // // When using OTP with counters, the counter is **NOT** // increased merely because this endpoint created // an OTP code (this is a GET request, after all!). // // If the otp_algorithm requires an amount, the // amount argument must be specified in the // query, otherwise the otp_code is not // generated. // // This field is *optional* in the response, as it is // only provided if we could compute it based on the // otp_algorithm and matching client query arguments. // // Available since protocol **v10**. otp_code?: string; } export 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; // Key-value pairs matching a subset of the // fields from template_contract that are // user-editable defaults for this template. // Since protocol **v13**. editable_defaults?: TemplateContractDetailsDefaults; // Required currency for payments. Useful if no // amount is specified in the template_contract // but the user should be required to pay in a // particular currency anyway. Merchant backends // may reject requests if the template_contract // or editable_defaults do // specify an amount in a different currency. // This parameter is optional. // Since protocol **v13**. required_currency?: string; } export 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; } export interface TemplateContractDetailsDefaults { summary?: string; currency?: string; amount?: AmountString; minimum_age?: Integer; pay_duration?: RelativeTime; } export 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; // Key-value pairs matching a subset of the // fields from template_contract that are // user-editable defaults for this template. // Since protocol **v13**. editable_defaults?: TemplateContractDetailsDefaults; // Required currency for payments. Useful if no // amount is specified in the template_contract // but the user should be required to pay in a // particular currency anyway. Merchant backends // may reject requests if the template_contract // or editable_defaults do // specify an amount in a different currency. // This parameter is optional. // Since protocol **v13**. required_currency?: string; } export interface TemplateSummaryResponse { // List of templates that are present in our backend. templates: TemplateEntry[]; } export interface TemplateEntry { // Template identifier, as found in the template. template_id: string; // Human-readable description for the template. template_description: string; } export interface WalletTemplateDetails { // Hard-coded information about the contrac terms // for this template. template_contract: TemplateContractDetails; // Key-value pairs matching a subset of the // fields from template_contract that are // user-editable defaults for this template. // Since protocol **v13**. editable_defaults?: TemplateContractDetailsDefaults; // Required currency for payments. Useful if no // amount is specified in the template_contract // but the user should be required to pay in a // particular currency anyway. Merchant backends // may reject requests if the template_contract // or editable_defaults do // specify an amount in a different currency. // This parameter is optional. // Since protocol **v13**. required_currency?: string; } export 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; // Key-value pairs matching a subset of the // fields from template_contract that are // user-editable defaults for this template. // Since protocol **v13**. editable_defaults?: TemplateContractDetailsDefaults; // Required currency for payments. Useful if no // amount is specified in the template_contract // but the user should be required to pay in a // particular currency anyway. Merchant backends // may reject requests if the template_contract // or editable_defaults do // specify an amount in a different currency. // This parameter is optional. // Since protocol **v13**. required_currency?: string; } export interface UsingTemplateDetails { // Summary of the template summary?: string; // The amount entered by the customer. amount?: AmountString; } export 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; } export 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; } export interface WebhookSummaryResponse { // Return webhooks that are present in our backend. webhooks: WebhookEntry[]; } export 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; } export 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; } export interface TokenFamilyCreateRequest { // Identifier for the token family consisting of unreserved characters // according to RFC 3986. slug: string; // Human-readable name for the token family. name: string; // Human-readable description for the token family. description: string; // Optional map from IETF BCP 47 language tags to localized descriptions. description_i18n?: { [lang_tag: string]: string }; // Start time of the token family's validity period. // If not specified, merchant backend will use the current time. valid_after?: Timestamp; // End time of the token family's validity period. valid_before: Timestamp; // Validity duration of an issued token. duration: RelativeTime; // Kind of the token family. kind: TokenFamilyKind; } export enum TokenFamilyKind { Discount = "discount", Subscription = "subscription", } export interface TokenFamilyUpdateRequest { // Human-readable name for the token family. name: string; // Human-readable description for the token family. description: string; // Optional map from IETF BCP 47 language tags to localized descriptions. description_i18n: { [lang_tag: string]: string }; // Start time of the token family's validity period. valid_after: Timestamp; // End time of the token family's validity period. valid_before: Timestamp; // Validity duration of an issued token. duration: RelativeTime; } export interface TokenFamiliesList { // All configured token families of this instance. token_families: TokenFamilySummary[]; } export interface TokenFamilySummary { // Identifier for the token family consisting of unreserved characters // according to RFC 3986. slug: string; // Human-readable name for the token family. name: string; // Start time of the token family's validity period. valid_after: Timestamp; // End time of the token family's validity period. valid_before: Timestamp; // Kind of the token family. kind: TokenFamilyKind; } export interface TokenFamilyDetails { // Identifier for the token family consisting of unreserved characters // according to RFC 3986. slug: string; // Human-readable name for the token family. name: string; // Human-readable description for the token family. description: string; // Optional map from IETF BCP 47 language tags to localized descriptions. description_i18n?: { [lang_tag: string]: string }; // Start time of the token family's validity period. valid_after: Timestamp; // End time of the token family's validity period. valid_before: Timestamp; // Validity duration of an issued token. duration: RelativeTime; // Kind of the token family. kind: TokenFamilyKind; // How many tokens have been issued for this family. issued: Integer; // How many tokens have been redeemed for this family. redeemed: Integer; } export 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; // Minimum age the buyer must have (in years). Default is 0. // This value is at least as large as the maximum over all // minimum age requirements of the products in this contract. // It might also be set independent of any product, due to // legal requirements. minimum_age?: Integer; } export 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; } export interface Tax { // The name of the tax. name: string; // Amount paid in tax. tax: AmountString; } export 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. export 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; } export 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; } } export namespace ChallengerApi { export interface ChallengerTermsOfServiceResponse { // Name of the service name: "challenger"; // libtool-style representation of the Challenger protocol version, see // https://www.gnu.org/software/libtool/manual/html_node/Versioning.html#Versioning // The format is "current:revision:age". version: string; // URN of the implementation (needed to interpret 'revision' in version). // @since v0, may become mandatory in the future. implementation?: string; } export interface ChallengeSetupResponse { // Nonce to use when constructing /authorize endpoint. nonce: string; } export interface ChallengeStatus { // Object; map of keys (names of the fields of the address // to be entered by the user) to objects with a "regex" (string) // containing an extended Posix regular expression for allowed // address field values, and a "hint"/"hint_i18n" giving a // human-readable explanation to display if the value entered // by the user does not match the regex. Keys that are not mapped // to such an object have no restriction on the value provided by // the user. See "ADDRESS_RESTRICTIONS" in the challenger configuration. restrictions: Object; // indicates if the given address cannot be changed anymore, the // form should be read-only if set to true. fix_address: boolean; // form values from the previous submission if available, details depend // on the ADDRESS_TYPE, should be used to pre-populate the form last_address: Object; // number of times the address can still be changed, may or may not be // shown to the user changes_left: Integer; } export interface ChallengeCreateResponse { // how many more attempts are allowed, might be shown to the user, // highlighting might be appropriate for low values such as 1 or 2 (the // form will never be used if the value is zero) attempts_left: Integer; // the address that is being validated, might be shown or not address: Object; // true if we just retransmitted the challenge, false if we sent a // challenge recently and thus refused to transmit it again this time; // might make a useful hint to the user transmitted: boolean; // timestamp explaining when we would re-transmit the challenge the next // time (at the earliest) if requested by the user next_tx_time: String; } export interface InvalidPinResponse { // numeric Taler error code, should be shown to indicate the error // compactly for reporting to developers ec: Integer; // human-readable Taler error code, should be shown for the user to // understand the error hint: String; // how many times is the user still allowed to change the address; // if 0, the user should not be shown a link to jump to the // address entry form addresses_left: Integer; // how many times might the PIN still be retransmitted pin_transmissions_left: Integer; // how many times might the user still try entering the PIN code auth_attempts_left: Integer; // if true, the PIN was not even evaluated as the user previously // exhausted the number of attempts exhausted: boolean; // if true, the PIN was not even evaluated as no challenge was ever // issued (the user must have skipped the step of providing their // address first!) no_challenge: boolean; } export interface ChallengerAuthResponse { // Token used to authenticate access in /info. access_token: string; // Type of the access token. token_type: "Bearer"; // Amount of time that an access token is valid (in seconds). expires_in: Integer; } export interface ChallengerInfoResponse { // Unique ID of the record within Challenger // (identifies the rowid of the token). id: Integer; // Address that was validated. // Key-value pairs, details depend on the // address_type. address: Object; // Type of the address. address_type: string; // How long do we consider the address to be // valid for this user. expires: Timestamp; } }