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