diff options
Diffstat (limited to 'packages/taler-util/src/http-client/types.ts')
-rw-r--r-- | packages/taler-util/src/http-client/types.ts | 5392 |
1 files changed, 5392 insertions, 0 deletions
diff --git a/packages/taler-util/src/http-client/types.ts b/packages/taler-util/src/http-client/types.ts new file mode 100644 index 000000000..a2f709769 --- /dev/null +++ b/packages/taler-util/src/http-client/types.ts @@ -0,0 +1,5392 @@ +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, + InternationalizedString, + 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:<mediatype>;base64,<data> +// +// 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; +} +/** + * Convert 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<AccessToken>; +export const codecForTokenSuccessResponse = + (): Codec<TalerAuthentication.TokenSuccessResponse> => + buildCodecForObject<TalerAuthentication.TokenSuccessResponse>() + .property("access_token", codecForAccessToken()) + .property("expiration", codecForTimestamp) + .build("TalerAuthentication.TokenSuccessResponse"); + +export const codecForTokenSuccessResponseMerchant = + (): Codec<TalerAuthentication.TokenSuccessResponseMerchant> => + buildCodecForObject<TalerAuthentication.TokenSuccessResponseMerchant>() + .property("token", codecForAccessToken()) + .property("expiration", codecForTimestamp) + .build("TalerAuthentication.TokenSuccessResponseMerchant"); + +export const codecForCurrencySpecificiation = + (): Codec<CurrencySpecification> => + buildCodecForObject<CurrencySpecification>() + .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<TalerCorebankApi.IntegrationConfig> => + buildCodecForObject<TalerCorebankApi.IntegrationConfig>() + .property("name", codecForConstString("taler-bank-integration")) + .property("version", codecForString()) + .property("currency", codecForString()) + .property("currency_specification", codecForCurrencySpecificiation()) + .build("TalerCorebankApi.IntegrationConfig"); + +export const codecForCoreBankConfig = (): Codec<TalerCorebankApi.Config> => + buildCodecForObject<TalerCorebankApi.Config>() + .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<TalerMerchantApi.ExchangeConfigInfo> => + buildCodecForObject<TalerMerchantApi.ExchangeConfigInfo>() + .property("base_url", codecForString()) + .property("currency", codecForString()) + .property("master_pub", codecForString()) + .build("TalerMerchantApi.ExchangeConfigInfo"); + +export const codecForMerchantConfig = + (): Codec<TalerMerchantApi.VersionResponse> => + buildCodecForObject<TalerMerchantApi.VersionResponse>() + .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<TalerMerchantApi.ClaimResponse> => + buildCodecForObject<TalerMerchantApi.ClaimResponse>() + .property("contract_terms", codecForContractTerms()) + .property("sig", codecForString()) + .build("TalerMerchantApi.ClaimResponse"); + +export const codecForPaymentResponse = + (): Codec<TalerMerchantApi.PaymentResponse> => + buildCodecForObject<TalerMerchantApi.PaymentResponse>() + .property("pos_confirmation", codecOptional(codecForString())) + .property("sig", codecForString()) + .build("TalerMerchantApi.PaymentResponse"); + +export const codecForStatusPaid = (): Codec<TalerMerchantApi.StatusPaid> => + buildCodecForObject<TalerMerchantApi.StatusPaid>() + .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<TalerMerchantApi.StatusGotoResponse> => + buildCodecForObject<TalerMerchantApi.StatusGotoResponse>() + .property("public_reorder_url", codecForURL()) + .property("type", codecForConstString("goto")) + .build("TalerMerchantApi.StatusGotoResponse"); + +export const codecForStatusStatusUnpaid = + (): Codec<TalerMerchantApi.StatusUnpaidResponse> => + buildCodecForObject<TalerMerchantApi.StatusUnpaidResponse>() + .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<TalerMerchantApi.PaidRefundStatusResponse> => + buildCodecForObject<TalerMerchantApi.PaidRefundStatusResponse>() + .property("pos_confirmation", codecOptional(codecForString())) + .property("refunded", codecForBoolean()) + .build("TalerMerchantApi.PaidRefundStatusResponse"); + +export const codecForMerchantAbortPayRefundSuccessStatus = + (): Codec<TalerMerchantApi.MerchantAbortPayRefundSuccessStatus> => + buildCodecForObject<TalerMerchantApi.MerchantAbortPayRefundSuccessStatus>() + .property("exchange_pub", codecForString()) + .property("exchange_sig", codecForString()) + .property("exchange_status", codecForConstNumber(200)) + .property("type", codecForConstString("success")) + .build("TalerMerchantApi.MerchantAbortPayRefundSuccessStatus"); + +export const codecForMerchantAbortPayRefundFailureStatus = + (): Codec<TalerMerchantApi.MerchantAbortPayRefundFailureStatus> => + buildCodecForObject<TalerMerchantApi.MerchantAbortPayRefundFailureStatus>() + .property("exchange_code", codecForNumber()) + .property("exchange_reply", codecForAny()) + .property("exchange_status", codecForNumber()) + .property("type", codecForConstString("failure")) + .build("TalerMerchantApi.MerchantAbortPayRefundFailureStatus"); + +export const codecForMerchantAbortPayRefundStatus = + (): Codec<TalerMerchantApi.MerchantAbortPayRefundStatus> => + buildCodecForUnion<TalerMerchantApi.MerchantAbortPayRefundStatus>() + .discriminateOn("type") + .alternative("success", codecForMerchantAbortPayRefundSuccessStatus()) + .alternative("failure", codecForMerchantAbortPayRefundFailureStatus()) + .build("TalerMerchantApi.MerchantAbortPayRefundStatus"); + +export const codecForAbortResponse = + (): Codec<TalerMerchantApi.AbortResponse> => + buildCodecForObject<TalerMerchantApi.AbortResponse>() + .property("refunds", codecForList(codecForMerchantAbortPayRefundStatus())) + .build("TalerMerchantApi.AbortResponse"); + +export const codecForWalletRefundResponse = + (): Codec<TalerMerchantApi.WalletRefundResponse> => + buildCodecForObject<TalerMerchantApi.WalletRefundResponse>() + .property("merchant_pub", codecForString()) + .property("refund_amount", codecForAmountString()) + .property("refunds", codecForList(codecForMerchantCoinRefundStatus())) + .build("TalerMerchantApi.AbortResponse"); + +export const codecForMerchantCoinRefundSuccessStatus = + (): Codec<TalerMerchantApi.MerchantCoinRefundSuccessStatus> => + buildCodecForObject<TalerMerchantApi.MerchantCoinRefundSuccessStatus>() + .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<TalerMerchantApi.MerchantCoinRefundFailureStatus> => + buildCodecForObject<TalerMerchantApi.MerchantCoinRefundFailureStatus>() + .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<TalerMerchantApi.MerchantCoinRefundStatus> => + buildCodecForUnion<TalerMerchantApi.MerchantCoinRefundStatus>() + .discriminateOn("type") + .alternative("success", codecForMerchantCoinRefundSuccessStatus()) + .alternative("failure", codecForMerchantCoinRefundFailureStatus()) + .build("TalerMerchantApi.MerchantCoinRefundStatus"); + +export const codecForQueryInstancesResponse = + (): Codec<TalerMerchantApi.QueryInstancesResponse> => + buildCodecForObject<TalerMerchantApi.QueryInstancesResponse>() + .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<TalerMerchantApi.AccountKycRedirects> => + buildCodecForObject<TalerMerchantApi.AccountKycRedirects>() + .property( + "pending_kycs", + codecForList(codecForMerchantAccountKycRedirect()), + ) + .property("timeout_kycs", codecForList(codecForExchangeKycTimeout())) + + .build("TalerMerchantApi.AccountKycRedirects"); + +export const codecForMerchantAccountKycRedirect = + (): Codec<TalerMerchantApi.MerchantAccountKycRedirect> => + buildCodecForObject<TalerMerchantApi.MerchantAccountKycRedirect>() + .property("kyc_url", codecForURL()) + .property("aml_status", codecForNumber()) + .property("exchange_url", codecForURL()) + .property("payto_uri", codecForPaytoString()) + .build("TalerMerchantApi.MerchantAccountKycRedirect"); + +export const codecForExchangeKycTimeout = + (): Codec<TalerMerchantApi.ExchangeKycTimeout> => + buildCodecForObject<TalerMerchantApi.ExchangeKycTimeout>() + .property("exchange_url", codecForURL()) + .property("exchange_code", codecForNumber()) + .property("exchange_http_status", codecForNumber()) + .build("TalerMerchantApi.ExchangeKycTimeout"); + +export const codecForAccountAddResponse = + (): Codec<TalerMerchantApi.AccountAddResponse> => + buildCodecForObject<TalerMerchantApi.AccountAddResponse>() + .property("h_wire", codecForString()) + .property("salt", codecForString()) + .build("TalerMerchantApi.AccountAddResponse"); + +export const codecForAccountsSummaryResponse = + (): Codec<TalerMerchantApi.AccountsSummaryResponse> => + buildCodecForObject<TalerMerchantApi.AccountsSummaryResponse>() + .property("accounts", codecForList(codecForBankAccountSummaryEntry())) + .build("TalerMerchantApi.AccountsSummaryResponse"); + +export const codecForBankAccountSummaryEntry = + (): Codec<TalerMerchantApi.BankAccountSummaryEntry> => + buildCodecForObject<TalerMerchantApi.BankAccountSummaryEntry>() + .property("payto_uri", codecForPaytoString()) + .property("h_wire", codecForString()) + .build("TalerMerchantApi.BankAccountSummaryEntry"); + +export const codecForBankAccountEntry = + (): Codec<TalerMerchantApi.BankAccountEntry> => + buildCodecForObject<TalerMerchantApi.BankAccountEntry>() + .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<TalerMerchantApi.InventorySummaryResponse> => + buildCodecForObject<TalerMerchantApi.InventorySummaryResponse>() + .property("products", codecForList(codecForInventoryEntry())) + .build("TalerMerchantApi.InventorySummaryResponse"); + +export const codecForInventoryEntry = + (): Codec<TalerMerchantApi.InventoryEntry> => + buildCodecForObject<TalerMerchantApi.InventoryEntry>() + .property("product_id", codecForString()) + .property("product_serial", codecForNumber()) + .build("TalerMerchantApi.InventoryEntry"); + +export const codecForProductDetail = + (): Codec<TalerMerchantApi.ProductDetail> => + buildCodecForObject<TalerMerchantApi.ProductDetail>() + .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<TalerMerchantApi.Tax> => + buildCodecForObject<TalerMerchantApi.Tax>() + .property("name", codecForString()) + .property("tax", codecForAmountString()) + .build("TalerMerchantApi.Tax"); + +export const codecForPostOrderResponse = + (): Codec<TalerMerchantApi.PostOrderResponse> => + buildCodecForObject<TalerMerchantApi.PostOrderResponse>() + .property("order_id", codecForString()) + .property("token", codecOptional(codecForString())) + .build("TalerMerchantApi.PostOrderResponse"); + +export const codecForOutOfStockResponse = + (): Codec<TalerMerchantApi.OutOfStockResponse> => + buildCodecForObject<TalerMerchantApi.OutOfStockResponse>() + .property("product_id", codecForString()) + .property("available_quantity", codecForNumber()) + .property("requested_quantity", codecForNumber()) + .property("restock_expected", codecForTimestamp) + .build("TalerMerchantApi.OutOfStockResponse"); + +export const codecForOrderHistory = (): Codec<TalerMerchantApi.OrderHistory> => + buildCodecForObject<TalerMerchantApi.OrderHistory>() + .property("orders", codecForList(codecForOrderHistoryEntry())) + .build("TalerMerchantApi.OrderHistory"); + +export const codecForOrderHistoryEntry = + (): Codec<TalerMerchantApi.OrderHistoryEntry> => + buildCodecForObject<TalerMerchantApi.OrderHistoryEntry>() + .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<TalerMerchantApi.Merchant> => + buildCodecForObject<TalerMerchantApi.Merchant>() + .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<TalerMerchantApi.Exchange> => + buildCodecForObject<TalerMerchantApi.Exchange>() + .property("master_pub", codecForString()) + .property("priority", codecForNumber()) + .property("url", codecForString()) + .build("TalerMerchantApi.Exchange"); + +export const codecForContractTerms = + (): Codec<TalerMerchantApi.ContractTerms> => + buildCodecForObject<TalerMerchantApi.ContractTerms>() + .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<TalerMerchantApi.Product> => + buildCodecForObject<TalerMerchantApi.Product>() + .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<TalerMerchantApi.CheckPaymentPaidResponse> => + buildCodecForObject<TalerMerchantApi.CheckPaymentPaidResponse>() + .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<TalerMerchantApi.CheckPaymentUnpaidResponse> => + buildCodecForObject<TalerMerchantApi.CheckPaymentUnpaidResponse>() + .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<TalerMerchantApi.CheckPaymentClaimedResponse> => + buildCodecForObject<TalerMerchantApi.CheckPaymentClaimedResponse>() + .property("order_status", codecForConstString("claimed")) + .property("contract_terms", codecForContractTerms()) + .build("TalerMerchantApi.CheckPaymentClaimedResponse"); + +export const codecForMerchantOrderPrivateStatusResponse = + (): Codec<TalerMerchantApi.MerchantOrderStatusResponse> => + buildCodecForUnion<TalerMerchantApi.MerchantOrderStatusResponse>() + .discriminateOn("order_status") + .alternative("paid", codecForCheckPaymentPaidResponse()) + .alternative("unpaid", codecForCheckPaymentUnpaidResponse()) + .alternative("claimed", codecForCheckPaymentClaimedResponse()) + .build("TalerMerchantApi.MerchantOrderStatusResponse"); + +export const codecForRefundDetails = + (): Codec<TalerMerchantApi.RefundDetails> => + buildCodecForObject<TalerMerchantApi.RefundDetails>() + .property("reason", codecForString()) + .property("pending", codecForBoolean()) + .property("timestamp", codecForTimestamp) + .property("amount", codecForAmountString()) + .build("TalerMerchantApi.RefundDetails"); + +export const codecForTransactionWireTransfer = + (): Codec<TalerMerchantApi.TransactionWireTransfer> => + buildCodecForObject<TalerMerchantApi.TransactionWireTransfer>() + .property("exchange_url", codecForURL()) + .property("wtid", codecForString()) + .property("execution_time", codecForTimestamp) + .property("amount", codecForAmountString()) + .property("confirmed", codecForBoolean()) + .build("TalerMerchantApi.TransactionWireTransfer"); + +export const codecForTransactionWireReport = + (): Codec<TalerMerchantApi.TransactionWireReport> => + buildCodecForObject<TalerMerchantApi.TransactionWireReport>() + .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<TalerMerchantApi.MerchantRefundResponse> => + buildCodecForObject<TalerMerchantApi.MerchantRefundResponse>() + .property("taler_refund_uri", codecForTalerUriString()) + .property("h_contract", codecForString()) + .build("TalerMerchantApi.MerchantRefundResponse"); + +export const codecForTansferList = (): Codec<TalerMerchantApi.TransferList> => + buildCodecForObject<TalerMerchantApi.TransferList>() + .property("transfers", codecForList(codecForTransferDetails())) + .build("TalerMerchantApi.TransferList"); + +export const codecForTransferDetails = + (): Codec<TalerMerchantApi.TransferDetails> => + buildCodecForObject<TalerMerchantApi.TransferDetails>() + .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<TalerMerchantApi.OtpDeviceSummaryResponse> => + buildCodecForObject<TalerMerchantApi.OtpDeviceSummaryResponse>() + .property("otp_devices", codecForList(codecForOtpDeviceEntry())) + .build("TalerMerchantApi.OtpDeviceSummaryResponse"); + +export const codecForOtpDeviceEntry = + (): Codec<TalerMerchantApi.OtpDeviceEntry> => + buildCodecForObject<TalerMerchantApi.OtpDeviceEntry>() + .property("otp_device_id", codecForString()) + .property("device_description", codecForString()) + .build("TalerMerchantApi.OtpDeviceEntry"); + +export const codecForOtpDeviceDetails = + (): Codec<TalerMerchantApi.OtpDeviceDetails> => + buildCodecForObject<TalerMerchantApi.OtpDeviceDetails>() + .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<TalerMerchantApi.TemplateSummaryResponse> => + buildCodecForObject<TalerMerchantApi.TemplateSummaryResponse>() + .property("templates", codecForList(codecForTemplateEntry())) + .build("TalerMerchantApi.TemplateSummaryResponse"); + +export const codecForTemplateEntry = + (): Codec<TalerMerchantApi.TemplateEntry> => + buildCodecForObject<TalerMerchantApi.TemplateEntry>() + .property("template_id", codecForString()) + .property("template_description", codecForString()) + .build("TalerMerchantApi.TemplateEntry"); + +export const codecForTemplateDetails = + (): Codec<TalerMerchantApi.TemplateDetails> => + buildCodecForObject<TalerMerchantApi.TemplateDetails>() + .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<TalerMerchantApi.TemplateContractDetails> => + buildCodecForObject<TalerMerchantApi.TemplateContractDetails>() + .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<TalerMerchantApi.TemplateContractDetailsDefaults> => + buildCodecForObject<TalerMerchantApi.TemplateContractDetailsDefaults>() + .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<TalerMerchantApi.WalletTemplateDetails> => + buildCodecForObject<TalerMerchantApi.WalletTemplateDetails>() + .property("template_contract", codecForTemplateContractDetails()) + .property("required_currency", codecOptional(codecForString())) + .property( + "editable_defaults", + codecOptional(codecForTemplateContractDetailsDefaults()), + ) + .build("TalerMerchantApi.WalletTemplateDetails"); + +export const codecForWebhookSummaryResponse = + (): Codec<TalerMerchantApi.WebhookSummaryResponse> => + buildCodecForObject<TalerMerchantApi.WebhookSummaryResponse>() + .property("webhooks", codecForList(codecForWebhookEntry())) + .build("TalerMerchantApi.WebhookSummaryResponse"); + +export const codecForWebhookEntry = (): Codec<TalerMerchantApi.WebhookEntry> => + buildCodecForObject<TalerMerchantApi.WebhookEntry>() + .property("webhook_id", codecForString()) + .property("event_type", codecForString()) + .build("TalerMerchantApi.WebhookEntry"); + +export const codecForWebhookDetails = + (): Codec<TalerMerchantApi.WebhookDetails> => + buildCodecForObject<TalerMerchantApi.WebhookDetails>() + .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<TalerMerchantApi.TokenFamilyKind> => + codecForEither( + codecForConstString("discount"), + codecForConstString("subscription"), + ) as any; //FIXME: create a codecForEnum +export const codecForTokenFamilyDetails = + (): Codec<TalerMerchantApi.TokenFamilyDetails> => + buildCodecForObject<TalerMerchantApi.TokenFamilyDetails>() + .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<TalerMerchantApi.TokenFamiliesList> => + buildCodecForObject<TalerMerchantApi.TokenFamiliesList>() + .property("token_families", codecForList(codecForTokenFamilySummary())) + .build("TalerMerchantApi.TokenFamiliesList"); + +export const codecForTokenFamilySummary = + (): Codec<TalerMerchantApi.TokenFamilySummary> => + buildCodecForObject<TalerMerchantApi.TokenFamilySummary>() + .property("slug", codecForString()) + .property("name", codecForString()) + .property("valid_after", codecForTimestamp) + .property("valid_before", codecForTimestamp) + .property("kind", codecForTokenFamilyKind()) + .build("TalerMerchantApi.TokenFamilySummary"); + +export const codecForInstancesResponse = + (): Codec<TalerMerchantApi.InstancesResponse> => + buildCodecForObject<TalerMerchantApi.InstancesResponse>() + .property("instances", codecForList(codecForInstance())) + .build("TalerMerchantApi.InstancesResponse"); + +export const codecForInstance = (): Codec<TalerMerchantApi.Instance> => + buildCodecForObject<TalerMerchantApi.Instance>() + .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<TalerExchangeApi.ExchangeVersionResponse> => + buildCodecForObject<TalerExchangeApi.ExchangeVersionResponse>() + .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<TalerExchangeApi.ExchangeKeysResponse> => + buildCodecForObject<TalerExchangeApi.ExchangeKeysResponse>() + .property("version", codecForString()) + .property("base_url", codecForString()) + .property("currency", codecForString()) + .build("TalerExchangeApi.ExchangeKeysResponse"); + +const codecForBalance = (): Codec<TalerCorebankApi.Balance> => + buildCodecForObject<TalerCorebankApi.Balance>() + .property("amount", codecForAmountString()) + .property( + "credit_debit_indicator", + codecForEither( + codecForConstString("credit"), + codecForConstString("debit"), + ), + ) + .build("TalerCorebankApi.Balance"); + +const codecForPublicAccount = (): Codec<TalerCorebankApi.PublicAccount> => + buildCodecForObject<TalerCorebankApi.PublicAccount>() + .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<TalerCorebankApi.PublicAccountsResponse> => + buildCodecForObject<TalerCorebankApi.PublicAccountsResponse>() + .property("public_accounts", codecForList(codecForPublicAccount())) + .build("TalerCorebankApi.PublicAccountsResponse"); + +export const codecForAccountMinimalData = + (): Codec<TalerCorebankApi.AccountMinimalData> => + buildCodecForObject<TalerCorebankApi.AccountMinimalData>() + .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<TalerCorebankApi.ListBankAccountsResponse> => + buildCodecForObject<TalerCorebankApi.ListBankAccountsResponse>() + .property("accounts", codecForList(codecForAccountMinimalData())) + .build("TalerCorebankApi.ListBankAccountsResponse"); + +export const codecForAccountData = (): Codec<TalerCorebankApi.AccountData> => + buildCodecForObject<TalerCorebankApi.AccountData>() + .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<TalerCorebankApi.ChallengeContactData> => + buildCodecForObject<TalerCorebankApi.ChallengeContactData>() + .property("email", codecOptional(codecForString())) + .property("phone", codecOptional(codecForString())) + .build("TalerCorebankApi.ChallengeContactData"); + +export const codecForWithdrawalPublicInfo = + (): Codec<TalerCorebankApi.WithdrawalPublicInfo> => + buildCodecForObject<TalerCorebankApi.WithdrawalPublicInfo>() + .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<TalerCorebankApi.BankAccountTransactionsResponse> => + buildCodecForObject<TalerCorebankApi.BankAccountTransactionsResponse>() + .property( + "transactions", + codecForList(codecForBankAccountTransactionInfo()), + ) + .build("TalerCorebankApi.BankAccountTransactionsResponse"); + +export const codecForBankAccountTransactionInfo = + (): Codec<TalerCorebankApi.BankAccountTransactionInfo> => + buildCodecForObject<TalerCorebankApi.BankAccountTransactionInfo>() + .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<TalerCorebankApi.CreateTransactionResponse> => + buildCodecForObject<TalerCorebankApi.CreateTransactionResponse>() + .property("row_id", codecForNumber()) + .build("TalerCorebankApi.CreateTransactionResponse"); + +export const codecForRegisterAccountResponse = + (): Codec<TalerCorebankApi.RegisterAccountResponse> => + buildCodecForObject<TalerCorebankApi.RegisterAccountResponse>() + .property("internal_payto_uri", codecForPaytoString()) + .build("TalerCorebankApi.RegisterAccountResponse"); + +export const codecForBankAccountCreateWithdrawalResponse = + (): Codec<TalerCorebankApi.BankAccountCreateWithdrawalResponse> => + buildCodecForObject<TalerCorebankApi.BankAccountCreateWithdrawalResponse>() + .property("taler_withdraw_uri", codecForTalerUriString()) + .property("withdrawal_id", codecForString()) + .build("TalerCorebankApi.BankAccountCreateWithdrawalResponse"); + +export const codecForCashoutPending = + (): Codec<TalerCorebankApi.CashoutResponse> => + buildCodecForObject<TalerCorebankApi.CashoutResponse>() + .property("cashout_id", codecForNumber()) + .build("TalerCorebankApi.CashoutPending"); + +export const codecForCashoutConversionResponse = + (): Codec<TalerBankConversionApi.CashoutConversionResponse> => + buildCodecForObject<TalerBankConversionApi.CashoutConversionResponse>() + .property("amount_credit", codecForAmountString()) + .property("amount_debit", codecForAmountString()) + .build("TalerCorebankApi.CashoutConversionResponse"); + +export const codecForCashinConversionResponse = + (): Codec<TalerBankConversionApi.CashinConversionResponse> => + buildCodecForObject<TalerBankConversionApi.CashinConversionResponse>() + .property("amount_credit", codecForAmountString()) + .property("amount_debit", codecForAmountString()) + .build("TalerCorebankApi.CashinConversionResponse"); + +export const codecForCashouts = (): Codec<TalerCorebankApi.Cashouts> => + buildCodecForObject<TalerCorebankApi.Cashouts>() + .property("cashouts", codecForList(codecForCashoutInfo())) + .build("TalerCorebankApi.Cashouts"); + +export const codecForCashoutInfo = (): Codec<TalerCorebankApi.CashoutInfo> => + buildCodecForObject<TalerCorebankApi.CashoutInfo>() + .property("cashout_id", codecForNumber()) + .build("TalerCorebankApi.CashoutInfo"); + +export const codecForGlobalCashouts = + (): Codec<TalerCorebankApi.GlobalCashouts> => + buildCodecForObject<TalerCorebankApi.GlobalCashouts>() + .property("cashouts", codecForList(codecForGlobalCashoutInfo())) + .build("TalerCorebankApi.GlobalCashouts"); + +export const codecForGlobalCashoutInfo = + (): Codec<TalerCorebankApi.GlobalCashoutInfo> => + buildCodecForObject<TalerCorebankApi.GlobalCashoutInfo>() + .property("cashout_id", codecForNumber()) + .property("username", codecForString()) + .build("TalerCorebankApi.GlobalCashoutInfo"); + +export const codecForCashoutStatusResponse = + (): Codec<TalerCorebankApi.CashoutStatusResponse> => + buildCodecForObject<TalerCorebankApi.CashoutStatusResponse>() + .property("amount_debit", codecForAmountString()) + .property("amount_credit", codecForAmountString()) + .property("subject", codecForString()) + .property("creation_time", codecForTimestamp) + .build("TalerCorebankApi.CashoutStatusResponse"); + +export const codecForConversionRatesResponse = + (): Codec<TalerCorebankApi.ConversionRatesResponse> => + buildCodecForObject<TalerCorebankApi.ConversionRatesResponse>() + .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<TalerCorebankApi.MonitorResponse> => + buildCodecForUnion<TalerCorebankApi.MonitorResponse>() + .discriminateOn("type") + .alternative("no-conversions", codecForMonitorNoConversion()) + .alternative("with-conversions", codecForMonitorWithCashout()) + .build("TalerWireGatewayApi.IncomingBankTransaction"); + +export const codecForMonitorNoConversion = + (): Codec<TalerCorebankApi.MonitorNoConversion> => + buildCodecForObject<TalerCorebankApi.MonitorNoConversion>() + .property("type", codecForConstString("no-conversions")) + .property("talerInCount", codecForNumber()) + .property("talerInVolume", codecForAmountString()) + .property("talerOutCount", codecForNumber()) + .property("talerOutVolume", codecForAmountString()) + .build("TalerCorebankApi.MonitorJustPayouts"); + +export const codecForMonitorWithCashout = + (): Codec<TalerCorebankApi.MonitorWithConversion> => + buildCodecForObject<TalerCorebankApi.MonitorWithConversion>() + .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<TalerBankIntegrationApi.BankVersion> => + buildCodecForObject<TalerBankIntegrationApi.BankVersion>() + .property("currency", codecForCurrencyName()) + .property("currency_specification", codecForCurrencySpecificiation()) + .property("name", codecForConstString("taler-bank-integration")) + .property("version", codecForLibtoolVersion()) + .build("TalerBankIntegrationApi.BankVersion"); + +export const codecForBankWithdrawalOperationStatus = + (): Codec<TalerBankIntegrationApi.BankWithdrawalOperationStatus> => + buildCodecForObject<TalerBankIntegrationApi.BankWithdrawalOperationStatus>() + .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<TalerBankIntegrationApi.BankWithdrawalOperationPostResponse> => + buildCodecForObject<TalerBankIntegrationApi.BankWithdrawalOperationPostResponse>() + .property( + "status", + codecForEither( + codecForConstString("selected"), + codecForConstString("aborted"), + codecForConstString("confirmed"), + ), + ) + .property("confirm_transfer_url", codecOptional(codecForURL())) + .build("TalerBankIntegrationApi.BankWithdrawalOperationPostResponse"); + +export const codecForRevenueConfig = (): Codec<TalerRevenueApi.RevenueConfig> => + buildCodecForObject<TalerRevenueApi.RevenueConfig>() + .property("name", codecForConstString("taler-revenue")) + .property("version", codecForString()) + .property("currency", codecForString()) + .property("implementation", codecOptional(codecForString())) + .build("TalerRevenueApi.RevenueConfig"); + +export const codecForRevenueIncomingHistory = + (): Codec<TalerRevenueApi.RevenueIncomingHistory> => + buildCodecForObject<TalerRevenueApi.RevenueIncomingHistory>() + .property("credit_account", codecForPaytoString()) + .property( + "incoming_transactions", + codecForList(codecForRevenueIncomingBankTransaction()), + ) + .build("TalerRevenueApi.MerchantIncomingHistory"); + +export const codecForRevenueIncomingBankTransaction = + (): Codec<TalerRevenueApi.RevenueIncomingBankTransaction> => + buildCodecForObject<TalerRevenueApi.RevenueIncomingBankTransaction>() + .property("amount", codecForAmountString()) + .property("date", codecForTimestamp) + .property("debit_account", codecForPaytoString()) + .property("row_id", codecForNumber()) + .property("subject", codecForString()) + .build("TalerRevenueApi.RevenueIncomingBankTransaction"); + +export const codecForTransferResponse = + (): Codec<TalerWireGatewayApi.TransferResponse> => + buildCodecForObject<TalerWireGatewayApi.TransferResponse>() + .property("row_id", codecForNumber()) + .property("timestamp", codecForTimestamp) + .build("TalerWireGatewayApi.TransferResponse"); + +export const codecForIncomingHistory = + (): Codec<TalerWireGatewayApi.IncomingHistory> => + buildCodecForObject<TalerWireGatewayApi.IncomingHistory>() + .property("credit_account", codecForPaytoString()) + .property( + "incoming_transactions", + codecForList(codecForIncomingBankTransaction()), + ) + .build("TalerWireGatewayApi.IncomingHistory"); + +export const codecForIncomingBankTransaction = + (): Codec<TalerWireGatewayApi.IncomingBankTransaction> => + buildCodecForUnion<TalerWireGatewayApi.IncomingBankTransaction>() + .discriminateOn("type") + .alternative("RESERVE", codecForIncomingReserveTransaction()) + .alternative("WAD", codecForIncomingWadTransaction()) + .build("TalerWireGatewayApi.IncomingBankTransaction"); + +export const codecForIncomingReserveTransaction = + (): Codec<TalerWireGatewayApi.IncomingReserveTransaction> => + buildCodecForObject<TalerWireGatewayApi.IncomingReserveTransaction>() + .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<TalerWireGatewayApi.IncomingWadTransaction> => + buildCodecForObject<TalerWireGatewayApi.IncomingWadTransaction>() + .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<TalerWireGatewayApi.OutgoingHistory> => + buildCodecForObject<TalerWireGatewayApi.OutgoingHistory>() + .property("debit_account", codecForPaytoString()) + .property( + "outgoing_transactions", + codecForList(codecForOutgoingBankTransaction()), + ) + .build("TalerWireGatewayApi.OutgoingHistory"); + +export const codecForOutgoingBankTransaction = + (): Codec<TalerWireGatewayApi.OutgoingBankTransaction> => + buildCodecForObject<TalerWireGatewayApi.OutgoingBankTransaction>() + .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<TalerWireGatewayApi.AddIncomingResponse> => + buildCodecForObject<TalerWireGatewayApi.AddIncomingResponse>() + .property("row_id", codecForNumber()) + .property("timestamp", codecForTimestamp) + .build("TalerWireGatewayApi.AddIncomingResponse"); + +export const codecForAmlRecords = (): Codec<TalerExchangeApi.AmlRecords> => + buildCodecForObject<TalerExchangeApi.AmlRecords>() + .property("records", codecForList(codecForAmlRecord())) + .build("TalerExchangeApi.PublicAccountsResponse"); + +export const codecForAmlRecord = (): Codec<TalerExchangeApi.AmlRecord> => + buildCodecForObject<TalerExchangeApi.AmlRecord>() + .property("current_state", codecForNumber()) + .property("h_payto", codecForString()) + .property("rowid", codecForNumber()) + .property("threshold", codecForAmountString()) + .build("TalerExchangeApi.AmlRecord"); + +export const codecForAmlDecisionDetails = + (): Codec<TalerExchangeApi.AmlDecisionDetails> => + buildCodecForObject<TalerExchangeApi.AmlDecisionDetails>() + .property("aml_history", codecForList(codecForAmlDecisionDetail())) + .property("kyc_attributes", codecForList(codecForKycDetail())) + .build("TalerExchangeApi.AmlDecisionDetails"); + +export const codecForAmlDecisionDetail = + (): Codec<TalerExchangeApi.AmlDecisionDetail> => + buildCodecForObject<TalerExchangeApi.AmlDecisionDetail>() + .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<TalerCorebankApi.Challenge> => + buildCodecForObject<TalerCorebankApi.Challenge>() + .property("challenge_id", codecForNumber()) + .build("TalerCorebankApi.Challenge"); + +export const codecForTanTransmission = + (): Codec<TalerCorebankApi.TanTransmission> => + buildCodecForObject<TalerCorebankApi.TanTransmission>() + .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<TalerExchangeApi.KycDetail> => + buildCodecForObject<TalerExchangeApi.KycDetail>() + .property("provider_section", codecForString()) + .property("attributes", codecOptional(codecForAny())) + .property("collection_time", codecForTimestamp) + .property("expiration_time", codecForTimestamp) + .build("TalerExchangeApi.KycDetail"); + +export const codecForAmlDecision = (): Codec<TalerExchangeApi.AmlDecision> => + buildCodecForObject<TalerExchangeApi.AmlDecision>() + .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<TalerBankConversionApi.ConversionInfo> => + buildCodecForObject<TalerBankConversionApi.ConversionInfo>() + .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<TalerBankConversionApi.IntegrationConfig> => + buildCodecForObject<TalerBankConversionApi.IntegrationConfig>() + .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<ChallengerApi.ChallengerTermsOfServiceResponse> => + buildCodecForObject<ChallengerApi.ChallengerTermsOfServiceResponse>() + .property("name", codecForConstString("challenger")) + .property("version", codecForString()) + .property("implementation", codecOptional(codecForString())) + .build("ChallengerApi.ChallengerTermsOfServiceResponse"); + +export const codecForChallengeSetupResponse = + (): Codec<ChallengerApi.ChallengeSetupResponse> => + buildCodecForObject<ChallengerApi.ChallengeSetupResponse>() + .property("nonce", codecForString()) + .build("ChallengerApi.ChallengeSetupResponse"); + +export const codecForChallengeStatus = + (): Codec<ChallengerApi.ChallengeStatus> => + buildCodecForObject<ChallengerApi.ChallengeStatus>() + .property("restrictions", codecOptional(codecForMap(codecForAny()))) + .property("fix_address", codecForBoolean()) + .property("last_address", codecOptional(codecForMap(codecForAny()))) + .property("changes_left", codecForNumber()) + .build("ChallengerApi.ChallengeStatus"); +export const codecForChallengeCreateResponse = + (): Codec<ChallengerApi.ChallengeCreateResponse> => + buildCodecForObject<ChallengerApi.ChallengeCreateResponse>() + .property("attempts_left", codecForNumber()) + .property("address", codecForAny()) + .property("transmitted", codecForBoolean()) + .property("next_tx_time", codecForString()) + .build("ChallengerApi.ChallengeCreateResponse"); + +export const codecForInvalidPinResponse = + (): Codec<ChallengerApi.InvalidPinResponse> => + buildCodecForObject<ChallengerApi.InvalidPinResponse>() + .property("ec", codecOptional(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<ChallengerApi.ChallengerAuthResponse> => + buildCodecForObject<ChallengerApi.ChallengerAuthResponse>() + .property("access_token", codecForString()) + .property("token_type", codecForAny()) + .property("expires_in", codecForNumber()) + .build("ChallengerApi.ChallengerAuthResponse"); + +export const codecForChallengerInfoResponse = + (): Codec<ChallengerApi.ChallengerInfoResponse> => + buildCodecForObject<ChallengerApi.ChallengerInfoResponse>() + .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 Restriction { + regex?: string; + hint?: string; + hint_i18n?: InternationalizedString; + } + + 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: Record<string, Restriction> | undefined; + + // 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: Record<string, string> | undefined; + + // 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?: number; + + // 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; + } +} |