/* This file is part of GNU Taler (C) 2021-2023 Taler Systems S.A. GNU Taler is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNU Taler; see the file COPYING. If not, see */ /** * * @author Sebastian Javier Marchano (sebasjm) */ type HashCode = string; type EddsaPublicKey = string; type EddsaSignature = string; type WireTransferIdentifierRawP = string; type RelativeTime = TalerProtocolDuration; type ImageDataUrl = string; type MerchantUserType = "business" | "individual"; export interface WithId { id: string; } interface Timestamp { // Milliseconds since epoch, or the special // value "forever" to represent an event that will // never happen. t_s: number | "never"; } interface TalerProtocolDuration { d_us: number | "forever"; } interface Duration { d_ms: number | "forever"; } interface WithId { id: string; } type Amount = string; type UUID = string; type Integer = number; interface WireAccount { // payto:// URI identifying the account and wire method payto_uri: string; // 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; } type AccountRestriction = RegexAccountRestriction | DenyAllAccountRestriction; // Account restriction that disables this type of // account for the indicated operation categorically. interface DenyAllAccountRestriction { type: "deny"; } // Accounts interacting with this type of account // restriction must have a payto://-URI matching // the given regex. interface RegexAccountRestriction { type: "regex"; // Regular expression that the payto://-URI of the // partner account must follow. 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 }; } interface LoginToken { token: string, expiration: Timestamp, } // token used to get loginToken // must forget after used declare const __ac_token: unique symbol; type AccessToken = string & { [__ac_token]: true; }; export namespace ExchangeBackend { interface WireResponse { // Master public key of the exchange, must match the key returned in /keys. master_public_key: EddsaPublicKey; // Array of wire accounts operated by the exchange for // incoming wire transfers. accounts: WireAccount[]; // Object mapping names of wire methods (i.e. "sepa" or "x-taler-bank") // to wire fees. fees: { method: AggregateTransferFee }; } interface AggregateTransferFee { // Per transfer wire transfer fee. wire_fee: Amount; // Per transfer closing fee. closing_fee: Amount; // 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; } } export namespace MerchantBackend { interface ErrorDetail { // Numeric error code unique to the condition. // The other arguments are specific to the error value reported here. code: number; // Human-readable description of the error, i.e. "missing parameter", "commitment violation", ... // Should give a human-readable hint about the error's nature. Optional, may change without notice! hint?: string; // Optional detail about the specific input value that failed. May change without notice! detail?: string; // Name of the parameter that was bogus (if applicable). parameter?: string; // Path to the argument that was bogus (if applicable). path?: string; // Offset of the argument that was bogus (if applicable). offset?: string; // Index of the argument that was bogus (if applicable). index?: string; // Name of the object that was bogus (if applicable). object?: string; // Name of the currency than was problematic (if applicable). currency?: string; // Expected type (if applicable). type_expected?: string; // Type that was provided instead (if applicable). type_actual?: string; } // Delivery location, loosely modeled as a subset of // ISO20022's PostalAddress25. interface Tax { // the name of the tax name: string; // amount paid in tax tax: Amount; } interface Auditor { // official name name: string; // Auditor's public key auditor_pub: EddsaPublicKey; // Base URL of the auditor url: string; } interface Exchange { // the exchange's base URL url: string; // master public key of the exchange master_pub: EddsaPublicKey; } 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; // The 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?: Amount; // 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?: TalerProtocolTimestamp; // Minimum age buyer must have (in years). Default is 0. minimum_age?: Integer; } interface Merchant { // label for a location with the business address of the merchant address: Location; // the merchant's legal name of business name: string; // 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; } interface VersionResponse { // libtool-style representation of the Merchant protocol version, see // https://www.gnu.org/software/libtool/manual/html_node/Versioning.html#Versioning // The format is "current:revision:age". version: string; // Name of the protocol. name: "taler-merchant"; // Default (!) currency supported by this backend. // This is the currency that the backend should // suggest by default to the user when entering // amounts. See currencies for a list of // supported currencies and how to render them. currency: string; // How 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: CurrencySpecification }; // Array of exchanges trusted by the merchant. // Since protocol v6. exchanges: ExchangeConfigInfo[]; } 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; } 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[]; } namespace Instances { //POST /private/instances/$INSTANCE/auth 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 "external", this field is mandatory. // The token MUST begin with the string "secret-token:". // After the auth token has been set (with method "token"), // the value must be provided in a "Authorization: Bearer $token" // header. token?: string; } //POST /private/instances interface InstanceConfigurationMessage { // Name of the merchant instance to create (will become $INSTANCE). 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?: MerchantUserType; // Merchant email for customer contact. email?: string; // Merchant public website. website?: string; // Merchant logo. logo?: ImageDataUrl; // "Authentication" header required to authorize management access the instance. // Optional, if not given authentication will be disabled for // this instance (hopefully authentication checks are still // done by some reverse proxy). 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; } // PATCH /private/instances/$INSTANCE 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?: MerchantUserType; // 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; } // GET /private/instances interface InstancesResponse { // List of instances that are present in the backend (see Instance) instances: Instance[]; } interface Instance { // Merchant name corresponding to this instance. name: string; // Type of the user ("business" or "individual"). user_type: MerchantUserType; // 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; } //GET /private/instances/$INSTANCE interface QueryInstancesResponse { // Merchant name corresponding to this instance. name: string; // Type of the user ("business" or "individual"). user_type: MerchantUserType; // 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"; }; } // DELETE /private/instances/$INSTANCE interface LoginTokenRequest { // Scope of the token (which kinds of operations it will allow) scope: "readonly" | "write"; // Server may impose its own upper bound // on the token validity duration duration?: RelativeTime; // Can this token be refreshed? // Defaults to false. refreshable?: boolean; } interface LoginTokenSuccessResponse { // The login token that can be used to access resources // that are in scope for some time. Must be prefixed // with "Bearer " when used in the "Authorization" HTTP header. // Will already begin with the RFC 8959 prefix. token: string; // Scope of the token (which kinds of operations it will allow) scope: "readonly" | "write"; // Server may impose its own upper bound // on the token validity duration expiration: Timestamp; // Can this token be refreshed? refreshable: boolean; } } namespace KYC { //GET /private/instances/$INSTANCE/kyc interface AccountKycRedirects { // Array of pending KYCs. pending_kycs: MerchantAccountKycRedirect[]; // Array of exchanges with no reply. timeout_kycs: ExchangeKycTimeout[]; } interface MerchantAccountKycRedirect { // URL that the user should open in a browser to // proceed with the KYC process (as returned // by the exchange's /kyc-check/ endpoint). // Optional, missing if the account is blocked // due to AML and not due to KYC. kyc_url?: string; // Base URL of the exchange this is about. exchange_url: string; // AML status of the account. aml_status: number; // Our bank wire account this is about. payto_uri: string; } 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; } } namespace BankAccounts { interface AccountAddDetails { // payto:// URI of the account. payto_uri: string; // URL from where the merchant can download information // about incoming wire transfers to this account. credit_facade_url?: string; // Credentials to use when accessing the credit facade. // Never returned on a GET (as this may be somewhat // sensitive data). Can be set in POST // or PATCH requests to update (or delete) credentials. // To really delete credentials, set them to the type: "none". credit_facade_credentials?: FacadeCredentials; } type FacadeCredentials = | NoFacadeCredentials | BasicAuthFacadeCredentials; interface NoFacadeCredentials { type: "none"; } interface BasicAuthFacadeCredentials { type: "basic"; // Username to use to authenticate username: string; // Password to use to authenticate password: string; } interface AccountAddResponse { // Hash over the wire details (including over the salt). h_wire: HashCode; // Salt used to compute h_wire. salt: HashCode; } interface AccountPatchDetails { // URL from where the merchant can download information // about incoming wire transfers to this account. credit_facade_url?: string; // Credentials to use when accessing the credit facade. // Never returned on a GET (as this may be somewhat // sensitive data). Can be set in POST // or PATCH requests to update (or delete) credentials. // To really delete credentials, set them to the type: "none". credit_facade_credentials?: FacadeCredentials; } interface AccountsSummaryResponse { // List of accounts that are known for the instance. accounts: BankAccountEntry[]; } interface BankAccountEntry { // payto:// URI of the account. payto_uri: string; // 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; // 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. credit_facade_credentials?: FacadeCredentials; // true if this account is active, // false if it is historic. active: boolean; } } namespace Products { // POST /private/products 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: Amount; // 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; } // PATCH /private/products/$PRODUCT_ID 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: Amount; // 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; } // GET /private/products interface InventorySummaryResponse { // List of products that are present in the inventory products: InventoryEntry[]; } interface InventoryEntry { // Product identifier, as found in the product. product_id: string; } // GET /private/products/$PRODUCT_ID 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: Amount; // 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). Default is 0. minimum_age?: Integer; } // POST /private/products/$PRODUCT_ID/lock interface LockRequest { // UUID that identifies the frontend performing the lock // It is suggested that clients use a timeflake for this, // see https://github.com/anthonynsimon/timeflake lock_uuid: UUID; // How long does the frontend intend to hold the lock duration: RelativeTime; // How many units should be locked? quantity: Integer; } // DELETE /private/products/$PRODUCT_ID } namespace Orders { type MerchantOrderStatusResponse = | CheckPaymentPaidResponse | CheckPaymentClaimedResponse | CheckPaymentUnpaidResponse; interface CheckPaymentPaidResponse { // The customer paid for this contract. order_status: "paid"; // Was the payment refunded (even partially)? refunded: boolean; // True if there are any approved refunds that the wallet has // not yet obtained. refund_pending: boolean; // Did the exchange wire us the funds? wired: boolean; // Total amount the exchange deposited into our bank account // for this contract, excluding fees. deposit_total: Amount; // 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_ec: 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_hc: number; // Total amount that was refunded, 0 if refunded is false. refund_amount: Amount; // Contract terms. contract_terms: ContractTerms; // The wire transfer status from the exchange for this order if // available, otherwise empty array. wire_details: TransactionWireTransfer[]; // The refund details for this order. One entry per // refunded coin; empty array if there are no refunds. refund_details: RefundDetails[]; // Status URL, can be used as a redirect target for the browser // to show the order QR code / trigger the wallet. order_status_url: string; } interface CheckPaymentClaimedResponse { // A wallet claimed the order, but did not yet pay for the contract. order_status: "claimed"; // Contract terms. contract_terms: ContractTerms; } interface CheckPaymentUnpaidResponse { // The order was neither claimed nor paid. order_status: "unpaid"; // 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: Amount; // URI that the wallet must process to complete the payment. taler_pay_uri: 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; // Fulfillment URL of an already paid order. Only given if under this // session an already paid order with a fulfillment URL exists. already_paid_fulfillment_url?: string; // Status URL, can be used as a redirect target for the browser // to show the order QR code / trigger the wallet. order_status_url: string; // We do we NOT return the contract terms here because they may not // exist in case the wallet did not yet claim them. } interface RefundDetails { // Reason given for the refund. reason: string; // When was the refund approved. timestamp: Timestamp; // Set to true if a refund is still available for the wallet for this payment. pending: boolean; // Total amount that was refunded (minus a refund fee). amount: Amount; } 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: Amount; // Was this transfer confirmed by the merchant via the // POST /transfers API, or is it merely claimed by the exchange? confirmed: boolean; } interface TransactionWireReport { // Numerical error code. code: number; // Human-readable error description. hint: string; // Numerical error code from the exchange. exchange_ec: number; // HTTP status code received from the exchange. exchange_hc: number; // Public key of the coin for which we got the exchange error. coin_pub: CoinPublicKey; } interface OrderHistory { // timestamp-sorted array of all orders matching the query. // The order of the sorting depends on the sign of delta. orders: OrderHistoryEntry[]; } interface OrderHistoryEntry { // order ID of the transaction related to this entry. order_id: string; // row ID of the order in the database row_id: number; // when the order was created timestamp: Timestamp; // the amount of money the order is for amount: Amount; // 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; } 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 // manage_inventory is set. Used in case a frontend // reserved quantities of the individual products while // the shopping card 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?: UUID[]; // 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: Amount; // Short summary of the order summary: 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). fulfillment_url?: string; } interface MinimalInventoryProduct { // Which product is requested (here mandatory!) product_id: string; // How many units of the product are requested quantity: Integer; } interface PostOrderResponse { // Order ID of the response that was just created order_id: string; // Token that authorizes the wallet to claim the order. // Provided only if "create_token" was set to 'true' // in the request. token?: ClaimToken; } interface OutOfStockResponse { // Product ID of an out-of-stock item product_id: string; // Requested quantity requested_quantity: Integer; // Available quantity (must be below requested_quanitity) available_quantity: Integer; // When do we expect the product to be again in stock? // Optional, not given if unknown. restock_expected?: Timestamp; } interface ForgetRequest { // Array of valid JSON paths to forgettable fields in the order's // contract terms. fields: string[]; } interface RefundRequest { // Amount to be refunded refund: Amount; // Human-readable refund justification reason: string; } interface MerchantRefundResponse { // URL (handled by the backend) that the wallet should access to // trigger refund processing. // taler://refund/... taler_refund_uri: string; // Contract hash that a client may need to authenticate an // HTTP request to obtain the above URI in a wallet-friendly way. h_contract: HashCode; } } namespace Rewards { // GET /private/reserves 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: Amount; // Initial amount as per exchange, 0 if exchange did // not confirm reserve creation yet. exchange_initial_amount: Amount; // Amount picked up so far. pickup_amount: Amount; // Amount approved for rewards that exceeds the pickup_amount. committed_amount: Amount; // Is this reserve active (false if it was deleted but not purged) active: boolean; } interface ReserveCreateRequest { // Amount that the merchant promises to put into the reserve initial_balance: Amount; // Exchange the merchant intends to use for reward 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: WireAccount[]; } interface RewardCreateRequest { // Amount that the customer should be reward amount: Amount; // Justification for giving the reward justification: string; // URL that the user should be directed to after rewarding, // 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 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: Amount; // Initial amount as per exchange, 0 if exchange did // not confirm reserve creation yet. exchange_initial_amount: Amount; // Amount picked up so far. pickup_amount: Amount; // Amount approved for rewards that exceeds the pickup_amount. committed_amount: Amount; // 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?: 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: Amount; // Human-readable reason for why the reward was granted. reason: string; } interface RewardDetails { // Amount that we authorized for this reward. total_authorized: Amount; // Amount that was picked up by the user already. total_picked_up: Amount; // 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: Amount; } } namespace Transfers { interface TransferList { // list of all the transfers that fit the filter that we know transfers: TransferDetails[]; } interface TransferDetails { // how much was wired to the merchant (minus fees) credit_amount: Amount; // raw wire transfer identifier identifying the wire transfer (a base32-encoded value) wtid: string; // target account that received the wire transfer payto_uri: string; // base URL of the exchange that made the wire transfer exchange_url: string; // Serial number identifying the transfer in the merchant backend. // Used for filgering 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 TransferInformation { // how much was wired to the merchant (minus fees) credit_amount: Amount; // raw wire transfer identifier identifying the wire transfer (a base32-encoded value) wtid: WireTransferIdentifierRawP; // target account that received the wire transfer payto_uri: string; // base URL of the exchange that made the wire transfer exchange_url: string; } } namespace OTP { interface OtpDeviceAddDetails { // Device ID to use. otp_device_id: string; // Human-readable description for the device. otp_device_description: string; // A base64-encoded key otp_key: string; // Algorithm for computing the POS confirmation. otp_algorithm: Integer; // Counter for counter-based OTP devices. otp_ctr?: Integer; } interface OtpDevicePatchDetails { // Human-readable description for the device. otp_device_description: string; // A base64-encoded key otp_key: string | undefined; // Algorithm for computing the POS confirmation. otp_algorithm: Integer; // Counter for counter-based OTP devices. otp_ctr?: Integer; } interface OtpDeviceSummaryResponse { // Array of devices that are present in our backend. otp_devices: OtpDeviceEntry[]; } interface OtpDeviceEntry { // Device identifier. otp_device_id: string; // Human-readable description for the device. device_description: string; } interface OtpDeviceDetails { // Human-readable description for the device. device_description: string; // Algorithm for computing the POS confirmation. otp_algorithm: Integer; // Counter for counter-based OTP devices. otp_ctr?: Integer; } } namespace Template { interface TemplateAddDetails { // Template ID to use. template_id: string; // Human-readable description for the template. template_description: string; // OTP device ID. // This parameter is optional. otp_id?: string; // Additional information in a separate template. template_contract: TemplateContractDetails; } interface TemplateContractDetails { // Human-readable summary for the template. summary?: string; // The price is imposed by the merchant and cannot be changed by the customer. // This parameter is optional. amount?: Amount; // Minimum age buyer must have (in years). Default is 0. minimum_age: Integer; // The time the customer need to pay before his order will be deleted. // It is deleted if the customer did not pay and if the duration is over. pay_duration: RelativeTime; } interface TemplatePatchDetails { // Human-readable description for the template. template_description: string; // OTP device ID. // This parameter is optional. otp_id?: string; // Additional information in a separate template. template_contract: TemplateContractDetails; } interface TemplateSummaryResponse { // List of templates that are present in our backend. templates: TemplateEntry[]; } interface TemplateEntry { // Template identifier, as found in the template. template_id: string; // Human-readable description for the template. template_description: string; } interface TemplateDetails { // Human-readable description for the template. template_description: string; // OTP device ID. // This parameter is optional. otp_id?: string; // Additional information in a separate template. template_contract: TemplateContractDetails; } interface UsingTemplateDetails { // Subject of the template summary?: string; // The amount entered by the customer. amount?: Amount; } interface UsingTemplateResponse { // After enter the request. The user will be pay with a taler URL. order_id: string; token: string; } } namespace Webhooks { type MerchantWebhookType = "pay" | "refund"; interface WebhookAddDetails { // Webhook ID to use. webhook_id: string; // The event of the webhook: why the webhook is used. event_type: MerchantWebhookType; // URL of the webhook where the customer will be redirected. url: string; // Method used by the webhook http_method: string; // Header template of the webhook header_template?: string; // Body template by the webhook body_template?: string; } interface WebhookPatchDetails { // The event of the webhook: why the webhook is used. event_type: string; // URL of the webhook where the customer will be redirected. url: string; // Method used by the webhook http_method: string; // Header template of the webhook header_template?: string; // Body template by the webhook body_template?: string; } interface WebhookSummaryResponse { // List of webhooks that are present in our backend. webhooks: WebhookEntry[]; } interface WebhookEntry { // Webhook identifier, as found in the webhook. webhook_id: string; // The event of the webhook: why the webhook is used. event_type: string; } interface WebhookDetails { // The event of the webhook: why the webhook is used. event_type: string; // URL of the webhook where the customer will be redirected. url: string; // Method used by the webhook http_method: string; // Header template of the webhook header_template?: string; // Body template by the webhook body_template?: string; } } interface ContractTerms { // Human-readable description of the whole purchase summary: string; // Map from IETF BCP 47 language tags to localized summaries summary_i18n?: { [lang_tag: string]: string }; // Unique, free-form identifier for the proposal. // Must be unique within a merchant instance. // For merchants that do not store proposals in their DB // before the customer paid for them, the order_id can be used // by the frontend to restore a proposal from the information // encoded in it (such as a short product identifier and timestamp). order_id: string; // Total price for the transaction. // The exchange will subtract deposit fees from that amount // before transferring it to the merchant. amount: Amount; // The URL for this purchase. Every time is is visited, the merchant // will send back to the customer the same proposal. Clearly, this URL // can be bookmarked and shared by users. fulfillment_url?: string; // Maximum total deposit fee accepted by the merchant for this contract max_fee: Amount; // List of products that are part of the purchase (see Product). products: Product[]; // Time when this contract was generated timestamp: TalerProtocolTimestamp; // After this deadline has passed, no refunds will be accepted. refund_deadline: TalerProtocolTimestamp; // After this deadline, the merchant won't accept payments for the contact pay_deadline: TalerProtocolTimestamp; // Transfer deadline for the exchange. Must be in the // deposit permissions of coins used to pay for this order. wire_transfer_deadline: TalerProtocolTimestamp; // 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; // Any exchanges audited by these auditors are accepted by the merchant. auditors: Auditor[]; // 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?: TalerProtocolTimestamp; // 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 buyer must have (in years). Default is 0. minimum_age?: Integer; } }