taler-docs

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

get-keys.rst (24018B)


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