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