taler-docs

Documentation for GNU Taler components, APIs and protocols
Log | Files | Refs | README | LICENSE

get-keys.rst (25615B)


      1 .. http:get:: /keys
      2 
      3   Get a list of all denomination keys offered by the exchange,
      4   as well as the exchange's current online signing key.
      5 
      6   **Request:**
      7 
      8   :query last_issue_date: Optional argument specifying the maximum value of any of the ``stamp_start`` members of the denomination keys of a ``/keys`` response that is already known to the client. Allows the exchange to only return keys that have changed since that timestamp.  The given value must be an unsigned 64-bit integer representing seconds after 1970.  If the timestamp does not exactly match the ``stamp_start`` of one of the denomination keys, all keys are returned.
      9   :query denom_filter: Optional denomination filter.  The value ``withdraw``
     10     requests only denominations relevant for upcoming withdrawals.  For every
     11     family identified by its cipher, value and age mask, the response contains
     12     all keys whose withdrawal validity interval includes the exchange's current
     13     time and all keys tied at the family's earliest future ``stamp_start``.
     14     Fees do not distinguish families.  Thus overlapping current keys are all
     15     included, while keys whose withdrawal validity ended and rotations after
     16     the immediate successor are omitted.  A selected key remains included with
     17     ``lost`` set even if its private key is unavailable.  Auditor metadata is
     18     unchanged, but its ``denomination_keys`` arrays contain signatures only for
     19     denominations included in the response.  This parameter is mutually
     20     exclusive with ``last_issue_date``.  If omitted, the exchange returns the
     21     existing complete or cherry-picked response.
     22 
     23   The filter does not change the response schema or signature format.  Clients
     24   using it must also accept a complete response, as older exchanges may ignore
     25   the additional query parameter.
     26 
     27   **Response:**
     28 
     29   :http:statuscode:`200 OK`:
     30     The exchange responds with a `ExchangeKeysResponse` object. This request should
     31     virtually always be successful. It only fails if the exchange is misconfigured or
     32     has not yet been provisioned with key signatures via ``taler-exchange-offline``.
     33   :http:statuscode:`400 Bad Request`:
     34     A query parameter is malformed, ``denom_filter`` has an unsupported value,
     35     or ``denom_filter`` and ``last_issue_date`` were both specified.
     36     This response comes with a standard `ErrorDetail` response with
     37     a code of ``TALER_EC_GENERIC_PARAMETER_MALFORMED``.
     38   :http:statuscode:`502 Bad Gateway`:
     39     A denomination or signing key helper is unavailable.
     40     This response comes with a standard `ErrorDetail` response with
     41     a code of ``TALER_EC_EXCHANGE_DENOMINATION_HELPER_UNAVAILABLE`` or
     42     ``TALER_EC_EXCHANGE_SIGNKEY_HELPER_UNAVAILABLE``.
     43   :http:statuscode:`500 Internal Server Error`:
     44     The server experienced an internal error.
     45     This response comes with a standard `ErrorDetail` response with
     46     a code of ``TALER_EC_GENERIC_JSON_ALLOCATION_FAILURE``.
     47   :http:statuscode:`503 Service Unavailable`:
     48     The exchange has no valid denomination keys available.  For a request with
     49     ``denom_filter=withdraw``, this also means that no current or future
     50     withdrawal denomination is available.
     51     This response comes with a standard `ErrorDetail` response with
     52     a code of ``TALER_EC_EXCHANGE_GENERIC_KEYS_MISSING``.
     53 
     54   **Details:**
     55 
     56   .. ts:def:: ExchangeKeysResponse
     57 
     58     interface ExchangeKeysResponse {
     59       // libtool-style representation of the Exchange protocol version, see
     60       // https://www.gnu.org/software/libtool/manual/html_node/Versioning.html#Versioning
     61       // The format is "current:revision:age".
     62       version: string;
     63 
     64       // The exchange's base URL.
     65       base_url: WebURL;
     66 
     67       // The exchange's currency or asset unit.
     68       currency: string;
     69 
     70       // Shopping URL where users may find shops that accept
     71       // digital cash issued by this exchange.
     72       // @since protocol **v21**.
     73       shopping_url?: WebURL;
     74 
     75       // Instructs wallets to use certain bank-specific
     76       // language (for buttons) and/or other UI/UX customization
     77       // for compliance with the rules of that bank.
     78       // The specific customizations to apply are done on a per-wallet
     79       // basis as requested by the specific bank. They only
     80       // apply when it is clear that the wallet is using digital
     81       // cash from that bank.  This is an advisory option, not
     82       // all wallets must support all compliance languages.
     83       // @since protocol **v24**.
     84       bank_compliance_language?: string;
     85 
     86       // How wallets should render this currency.
     87       currency_specification: CurrencySpecification;
     88 
     89       // Small(est?) amount that can likely be transferred to
     90       // the exchange. Should be the default amount for KYC
     91       // authentication wire transfers to this exchange.
     92       // @since protocol **v21**. Mandatory since **v33**.
     93       tiny_amount?: Amount;
     94 
     95       // Absolute cost offset for the STEFAN curve used
     96       // to (over) approximate fees payable by amount.
     97       stefan_abs: Amount;
     98 
     99       // Factor to multiply the logarithm of the amount
    100       // with to (over) approximate fees payable by amount.
    101       // Note that the total to be paid is first to be
    102       // divided by the smallest denomination to obtain
    103       // the value that the logarithm is to be taken of.
    104       stefan_log: Amount;
    105 
    106       // Linear cost factor for the STEFAN curve used
    107       // to (over) approximate fees payable by amount.
    108       //
    109       // Note that this is a scalar, as it is multiplied
    110       // with the actual amount.
    111       stefan_lin: Float;
    112 
    113       // Type of the asset. "fiat", "crypto", "regional"
    114       // or "stock".  Wallets should adjust their UI/UX
    115       // based on this value.
    116       asset_type: string;
    117 
    118       // Array of wire accounts operated by the exchange for
    119       // incoming wire transfers.
    120       accounts: ExchangeWireAccount[];
    121 
    122       // Object mapping names of wire methods (i.e. "iban" or "x-taler-bank")
    123       // to wire fees.
    124       wire_fees: { method : AggregateTransferFee[] };
    125 
    126       // List of exchanges that this exchange is partnering
    127       // with to enable wallet-to-wallet transfers.
    128       wads: ExchangePartnerListEntry[];
    129 
    130       // Set to true if this exchange allows the use
    131       // of reserves for rewards.
    132       // @deprecated in protocol **v18**.
    133       rewards_allowed: false;
    134 
    135       // Set to true if this exchange has KYC enabled and thus
    136       // requires KYC auth wire transfers prior to a first deposit.
    137       // @since protocol **v24**.
    138       kyc_enabled: boolean;
    139 
    140       // Signal to the merchant backend that it should swap
    141       // the terms-of-service and KYC auth authentication
    142       // steps in the user experience.  Optional, defaults
    143       // to false if not given.
    144       // @since protocol **v36**.
    145       kyc_swap_tos_acceptance?: boolean;
    146 
    147       // Set to TRUE if wallets should disable the direct deposit feature
    148       // and deposits should only go via Taler merchant APIs.
    149       // Mainly used for regional currency and event currency deployments
    150       // where wallets are not eligible to deposit back into originating
    151       // bank accounts and, because KYC is not enabled, wallets are thus
    152       // likely to send money to nirvana instead of where users want it.
    153       // @since protocol **v30**.
    154       disable_direct_deposit: boolean;
    155 
    156       // EdDSA master public key of the exchange, used to sign entries
    157       // in ``denoms`` and ``signkeys``.
    158       master_public_key: EddsaPublicKey;
    159 
    160       // Relative duration until inactive reserves are closed;
    161       // not signed (!), can change without notice.
    162       reserve_closing_delay: RelativeTime;
    163 
    164       // How long should a P2P push payment be valid by default.
    165       // @since protocol **v35**.
    166       default_p2p_push_expiration: RelativeTime;
    167 
    168       // How far in the future may the ``purse_expiration`` of a purse be?
    169       // An expiring purse refunds the coins deposited into it, and the
    170       // exchange must still be able to account for that refund, so a purse
    171       // may not outlive the denominations of the coins in it.  Applies to
    172       // both purse-creating endpoints, and in addition no coin may be
    173       // deposited into a purse that would outlive the
    174       // ``stamp_expire_legal`` of the coin's own denomination.
    175       // @since protocol **v42**.
    176       max_p2p_expiration: RelativeTime;
    177 
    178       // Threshold amounts beyond which wallet should
    179       // trigger the KYC process of the issuing exchange.
    180       // Optional option, if not given there is no limit.
    181       // Currency must match ``currency``.
    182       wallet_balance_limit_without_kyc?: Amount[];
    183 
    184       // Array of limits that apply to all accounts.
    185       // All of the given limits will be hard limits.
    186       // Wallets and merchants are expected to obey them
    187       // and not even allow the user to cross them.
    188       // @since protocol **v21**.
    189       hard_limits: AccountLimit[];
    190 
    191       // Array of limits with a soft threshold of zero
    192       // that apply to all accounts without KYC.
    193       // Wallets and merchants are expected to trigger
    194       // a KYC process before attempting any zero-limited
    195       // operations.
    196       // @since protocol **v21**.
    197       zero_limits: ZeroLimitedOperation[];
    198 
    199       // Denominations offered by this exchange
    200       denominations: DenomGroup[];
    201 
    202       // Compact EdDSA `signature` (binary-only) over the
    203       // contatentation of all of the master_sigs (in reverse
    204       // chronological order by group) in the arrays under
    205       // "denominations".  Signature of `TALER_ExchangeKeySetPS`
    206       exchange_sig: EddsaSignature;
    207 
    208       // Public EdDSA key of the exchange that was used to generate the signature.
    209       // Should match one of the exchange's signing keys from ``signkeys``.  It is given
    210       // explicitly as the client might otherwise be confused by clock skew as to
    211       // which signing key was used for the ``exchange_sig``.
    212       exchange_pub: EddsaPublicKey;
    213 
    214       // Denominations for which the exchange currently offers/requests recoup.
    215       recoup: RecoupDenoms[];
    216 
    217       // Array of globally applicable fees by time range.
    218       global_fees: GlobalFees[];
    219 
    220       // The date when the denomination keys were last updated.
    221       list_issue_date: Timestamp;
    222 
    223       // Auditors of the exchange.
    224       auditors: AuditorKeys[];
    225 
    226       // The exchange's signing keys.
    227       signkeys: SignKey[];
    228 
    229     }
    230 
    231   The specification for the account object is:
    232 
    233   .. ts:def:: ExchangeWireAccount
    234 
    235     interface ExchangeWireAccount {
    236       // Full ``payto://`` URI identifying the account and wire method
    237       payto_uri: string;
    238 
    239       // URI to convert amounts from or to the currency used by
    240       // this wire account of the exchange. Missing if no
    241       // conversion is applicable.
    242       conversion_url?: WebURL;
    243 
    244       // Open banking gateway base URL where wallets can
    245       // initiate wire transfers to withdraw
    246       // digital cash from this exchange.
    247       // @since protocol **v34**.
    248       open_banking_gateway?: WebURL;
    249 
    250       // Wire transfer gateway base URL where wallets and merchants can
    251       // request (short) wire transfer subjects to wire funds to this
    252       // exchange without having to encode the full public key.
    253       // @since protocol **v34**.
    254       prepared_transfer_url?: WebURL;
    255 
    256       // Restrictions that apply to bank accounts that would send
    257       // funds to the exchange (crediting this exchange bank account).
    258       // Optional, empty array for unrestricted.
    259       credit_restrictions: AccountRestriction[];
    260 
    261       // Restrictions that apply to bank accounts that would receive
    262       // funds from the exchange (debiting this exchange bank account).
    263       // Optional, empty array for unrestricted.
    264       debit_restrictions: AccountRestriction[];
    265 
    266       // Signature using the exchange's offline key over
    267       // a `TALER_MasterWireDetailsPS`
    268       // with purpose ``TALER_SIGNATURE_MASTER_WIRE_DETAILS``.
    269       master_sig: EddsaSignature;
    270 
    271       // Display label wallets should use to show this
    272       // bank account.
    273       // @since protocol **v19**.
    274       bank_label?: string;
    275 
    276       // *Signed* integer with the display priority for
    277       // this bank account. Optional, 0 if missing.
    278       // @since protocol **v19**.
    279       priority?: Integer;
    280 
    281     }
    282 
    283   .. ts:def:: AccountRestriction
    284 
    285     type AccountRestriction =
    286       | RegexAccountRestriction
    287       | DenyAllAccountRestriction
    288 
    289   .. ts:def:: DenyAllAccountRestriction
    290 
    291     // Account restriction that disables this type of
    292     // account for the indicated operation categorically.
    293     interface DenyAllAccountRestriction {
    294 
    295       type: "deny";
    296     }
    297 
    298   .. ts:def:: RegexAccountRestriction
    299 
    300     // Accounts interacting with this type of account
    301     // restriction must have a normalized payto://-URI matching
    302     // the given regex.
    303     interface RegexAccountRestriction {
    304 
    305       type: "regex";
    306 
    307       // Regular expression that the payto://-URI of the
    308       // partner account must follow.  The regular expression
    309       // should follow posix-egrep, but without support for character
    310       // classes, GNU extensions, back-references or intervals. See
    311       // https://www.gnu.org/software/findutils/manual/html_node/find_html/posix_002degrep-regular-expression-syntax.html
    312       // for a description of the posix-egrep syntax. Applications
    313       // may support regexes with additional features, but exchanges
    314       // must not use such regexes.
    315       payto_regex: string;
    316 
    317       // Hint for a human to understand the restriction
    318       // (that is hopefully easier to comprehend than the regex itself).
    319       human_hint: string;
    320 
    321       // Map from IETF BCP 47 language tags to localized
    322       // human hints.
    323       human_hint_i18n?: { [lang_tag: string]: string };
    324 
    325     }
    326 
    327   .. ts:def:: ZeroLimitedOperation
    328 
    329     interface ZeroLimitedOperation {
    330 
    331       // Operation that is limited to an amount of
    332       // zero until the client has passed some KYC check.
    333       // Must be one of "WITHDRAW", "DEPOSIT",
    334       // (p2p) "MERGE", (wallet) "BALANCE",
    335       // (reserve) "CLOSE", "AGGREGATE",
    336       // "TRANSACTION" or "REFUND".
    337       operation_type: string;
    338 
    339     }
    340 
    341 
    342   .. ts:def:: AccountLimit
    343 
    344     interface AccountLimit {
    345 
    346       // Operation that is limited.
    347       // Must be one of "WITHDRAW", "DEPOSIT",
    348       // (p2p) "MERGE", (wallet) "BALANCE",
    349       // (reserve) "CLOSE", "AGGREGATE",
    350       // "TRANSACTION" or "REFUND".
    351       operation_type: string;
    352 
    353       // Timeframe during which the limit applies.
    354       // Not applicable for all operation_types
    355       // (but always present in this object anyway).
    356       timeframe: RelativeTime;
    357 
    358       // Maximum amount allowed during the given timeframe.
    359       // Zero if the operation is simply forbidden.
    360       threshold: Amount;
    361 
    362       // True if this is a soft limit that could be raised
    363       // by passing KYC checks.  Clients *may* deliberately
    364       // try to cross limits and trigger measures resulting
    365       // in 451 responses to begin KYC processes.
    366       // Clients that are aware of hard limits *should*
    367       // inform users about the hard limit and prevent flows
    368       // in the UI that would cause violations of hard limits.
    369       // Made optional in **v21** with a default of 'false' if missing.
    370       soft_limit?: boolean;
    371     }
    372 
    373   .. ts:def:: GlobalFees
    374 
    375     interface GlobalFees {
    376 
    377       // What date (inclusive) does these fees go into effect?
    378       start_date: Timestamp;
    379 
    380       // What date (exclusive) does this fees stop going into effect?
    381       end_date: Timestamp;
    382 
    383       // Account history fee, charged when a user wants to
    384       // obtain a reserve/account history.
    385       history_fee: Amount;
    386 
    387       // Annual fee charged for having an open account at the
    388       // exchange.  Charged to the account.  If the account
    389       // balance is insufficient to cover this fee, the account
    390       // is automatically deleted/closed. (Note that the exchange
    391       // will keep the account history around for longer for
    392       // regulatory reasons.)
    393       account_fee: Amount;
    394 
    395       // Purse fee, charged only if a purse is abandoned
    396       // and was not covered by the account limit.
    397       purse_fee: Amount;
    398 
    399       // How long will the exchange preserve the account history?
    400       // After an account was deleted/closed, the exchange will
    401       // retain the account history for legal reasons until this time.
    402       history_expiration: RelativeTime;
    403 
    404       // Non-negative number of concurrent purses that any
    405       // account holder is allowed to create without having
    406       // to pay the purse_fee.
    407       purse_account_limit: Integer;
    408 
    409       // How long does an exchange keep a purse around after a purse
    410       // has expired (or been successfully merged)?  A 'GET' request
    411       // for a purse will succeed until the purse expiration time
    412       // plus this value.
    413       purse_timeout: RelativeTime;
    414 
    415       // Signature of `TALER_GlobalFeesPS`.
    416       master_sig: EddsaSignature;
    417 
    418     }
    419 
    420   .. ts:def:: DenomGroup
    421 
    422     type DenomGroup =
    423       | DenomGroupRsa
    424       | DenomGroupCs
    425       | DenomGroupRsaAgeRestricted
    426       | DenomGroupCsAgeRestricted;
    427 
    428   .. ts:def:: DenomGroupRsa
    429 
    430     interface DenomGroupRsa extends DenomGroupCommon {
    431       cipher: "RSA";
    432 
    433       denoms: ({
    434         rsa_pub: RsaPublicKey;
    435       } & DenomCommon)[];
    436     }
    437 
    438   .. ts:def:: DenomGroupCs
    439 
    440     interface DenomGroupCs extends DenomGroupCommon {
    441       cipher: "CS";
    442 
    443       denoms: ({
    444         cs_pub: Cs25519Point;
    445       } & DenomCommon)[];
    446     }
    447 
    448   .. ts:def:: DenomGroupRsaAgeRestricted
    449 
    450     interface DenomGroupRsaAgeRestricted extends DenomGroupCommon {
    451       cipher: "RSA+age_restricted";
    452       age_mask: AgeMask;
    453 
    454       denoms: ({
    455         rsa_pub: RsaPublicKey;
    456       } & DenomCommon)[];
    457     }
    458 
    459   .. ts:def:: DenomGroupCsAgeRestricted
    460 
    461     interface DenomGroupCsAgeRestricted extends DenomGroupCommon {
    462       cipher: "CS+age_restricted";
    463       age_mask: AgeMask;
    464 
    465       denoms: ({
    466         cs_pub: Cs25519Point;
    467       } & DenomCommon)[];
    468     }
    469 
    470   .. ts:def:: DenomGroupCommon
    471 
    472     // Common attributes for all denomination groups
    473     interface DenomGroupCommon {
    474       // How much are coins of this denomination worth?
    475       value: Amount;
    476 
    477       // Fee charged by the exchange for withdrawing a coin of this denomination.
    478       fee_withdraw: Amount;
    479 
    480       // Fee charged by the exchange for depositing a coin of this denomination.
    481       fee_deposit: Amount;
    482 
    483       // Fee charged by the exchange for refreshing a coin of this denomination.
    484       fee_refresh: Amount;
    485 
    486       // Fee charged by the exchange for refunding a coin of this denomination.
    487       fee_refund: Amount;
    488 
    489     }
    490 
    491   .. ts:def:: DenomCommon
    492 
    493     interface DenomCommon {
    494       // Signature of `TALER_DenominationKeyValidityPS`.
    495       master_sig: EddsaSignature;
    496 
    497       // When does the denomination key become valid?
    498       stamp_start: Timestamp;
    499 
    500       // When is it no longer possible to withdraw coins
    501       // of this denomination? Note that while this option
    502       // is given per denomination, all concurrently active
    503       // denominations (of the same cipher type)
    504       // will have exactly the same withdraw
    505       // expiration time. Thus, the wallet can be sure what
    506       // is the smallest denomination being offered at any
    507       // particular point in time, and not worry about the
    508       // exchange having merely failed to sign the key of
    509       // only the smallest denomination unit.
    510       stamp_expire_withdraw: Timestamp;
    511 
    512       // When is it no longer possible to deposit coins
    513       // of this denomination?
    514       stamp_expire_deposit: Timestamp;
    515 
    516       // Timestamp indicating by when legal disputes relating to these coins must
    517       // be settled, as the exchange will afterwards destroy its evidence relating to
    518       // transactions involving this coin.
    519       stamp_expire_legal: Timestamp;
    520 
    521       // Set to 'true' if the exchange somehow "lost"
    522       // the private key. The denomination was not
    523       // necessarily revoked, but still cannot be used
    524       // to withdraw coins at this time (theoretically,
    525       // the private key could be recovered in the
    526       // future; coins signed with the private key
    527       // remain valid).
    528       lost?: boolean;
    529     }
    530 
    531   Fees for any of the operations can be zero, but the fields must still be
    532   present. The currency of the ``fee_deposit``, ``fee_refresh`` and ``fee_refund`` must match the
    533   currency of the ``value``.  Theoretically, the ``fee_withdraw`` could be in a
    534   different currency, but this is not currently supported by the
    535   implementation.
    536 
    537   .. ts:def:: RecoupDenoms
    538 
    539     interface RecoupDenoms {
    540       // Hash of the public key of the denomination that is being revoked under
    541       // emergency protocol (see ``/recoup-withdraw`` and ``/recoup-refresh``).
    542       h_denom_pub: HashCode;
    543 
    544       // We do not include any signature here, as the primary use-case for
    545       // this emergency involves the exchange having lost its signing keys,
    546       // so such a signature here would be pretty worthless.  However, the
    547       // exchange will not honor ``/recoup-withdraw`` or ``/recoup-refresh``
    548       // requests unless they are for denomination keys listed here.
    549     }
    550 
    551   A signing key in the ``signkeys`` list is a JSON object with the following fields:
    552 
    553   .. ts:def:: SignKey
    554 
    555     interface SignKey {
    556       // The actual exchange's EdDSA signing public key.
    557       key: EddsaPublicKey;
    558 
    559       // Initial validity date for the signing key.
    560       stamp_start: Timestamp;
    561 
    562       // Date when the exchange will stop using the signing key, allowed to overlap
    563       // slightly with the next signing key's validity to allow for clock skew.
    564       stamp_expire: Timestamp;
    565 
    566       // Date when all signatures made by the signing key expire and should
    567       // henceforth no longer be considered valid in legal disputes.
    568       stamp_end: Timestamp;
    569 
    570       // Signature over ``key`` and ``stamp_expire`` by the exchange master key.
    571       // Signature of `TALER_ExchangeSigningKeyValidityPS`.
    572       // Must have purpose ``TALER_SIGNATURE_MASTER_SIGNING_KEY_VALIDITY``.
    573       master_sig: EddsaSignature;
    574     }
    575 
    576   An entry in the ``auditors`` list is a JSON object with the following fields:
    577 
    578   .. ts:def:: AuditorKeys
    579 
    580     interface AuditorKeys {
    581       // The auditor's EdDSA signing public key.
    582       auditor_pub: EddsaPublicKey;
    583 
    584       // The auditor's URL.
    585       auditor_url: WebURL;
    586 
    587       // The auditor's name (for humans).
    588       auditor_name: string;
    589 
    590       // An array of denomination keys the auditor affirms with its signature.
    591       // Note that the message only includes the hash of the public key, while the
    592       // signature is actually over the expanded information including expiration
    593       // times and fees.  The exact format is described below.
    594       denomination_keys: AuditorDenominationKey[];
    595     }
    596 
    597   .. ts:def:: AuditorDenominationKey
    598 
    599     interface AuditorDenominationKey {
    600       // Hash of the public RSA key used to sign coins of the respective
    601       // denomination.  Note that the auditor's signature covers more than just
    602       // the hash, but this other information is already provided in ``denoms`` and
    603       // thus not repeated here.
    604       denom_pub_h: HashCode;
    605 
    606       // Signature of `TALER_ExchangeKeyValidityPS`.
    607       auditor_sig: EddsaSignature;
    608     }
    609 
    610   The same auditor may appear multiple times in the array for different subsets
    611   of denomination keys, and the same denomination key hash may be listed
    612   multiple times for the same or different auditors.  The wallet or merchant
    613   just should check that the denomination keys they use are in the set for at
    614   least one of the auditors that they accept.
    615 
    616   .. note::
    617 
    618     Both the individual denominations *and* the denomination list is signed,
    619     allowing customers to prove that they received an inconsistent list.
    620 
    621   Aggregate wire transfer fees representing the fees the exchange
    622   charges per wire transfer to a merchant must be specified as an
    623   array in all wire transfer response objects under ``fees``.  The
    624   respective array contains objects with the following members:
    625 
    626   .. ts:def:: AggregateTransferFee
    627 
    628     interface AggregateTransferFee {
    629       // Per transfer wire transfer fee.
    630       wire_fee: Amount;
    631 
    632       // Per transfer closing fee.
    633       closing_fee: Amount;
    634 
    635       // What date (inclusive) does this fee go into effect?
    636       // The different fees must cover the full time period in which
    637       // any of the denomination keys are valid without overlap.
    638       start_date: Timestamp;
    639 
    640       // What date (exclusive) does this fee stop going into effect?
    641       // The different fees must cover the full time period in which
    642       // any of the denomination keys are valid without overlap.
    643       end_date: Timestamp;
    644 
    645       // Signature of `TALER_MasterWireFeePS` with
    646       // purpose ``TALER_SIGNATURE_MASTER_WIRE_FEES``.
    647       sig: EddsaSignature;
    648     }
    649 
    650   .. ts:def:: ExchangePartnerListEntry
    651 
    652     interface ExchangePartnerListEntry {
    653       // Base URL of the partner exchange.
    654       partner_base_url: WebURL;
    655 
    656       // Public master key of the partner exchange.
    657       partner_master_pub: EddsaPublicKey;
    658 
    659       // Per exchange-to-exchange transfer (wad) fee.
    660       wad_fee: Amount;
    661 
    662       // Exchange-to-exchange wad (wire) transfer frequency.
    663       wad_frequency: RelativeTime;
    664 
    665       // When did this partnership begin (under these conditions)?
    666       start_date: Timestamp;
    667 
    668       // How long is this partnership expected to last?
    669       end_date: Timestamp;
    670 
    671       // Signature using the exchange's offline key over
    672       // `TALER_WadPartnerSignaturePS`
    673       // with purpose ``TALER_SIGNATURE_MASTER_PARTNER_DETAILS``.
    674       master_sig: EddsaSignature;
    675     }