api-merchant.rst (215461B)
1 .. 2 This file is part of GNU TALER. 3 Copyright (C) 2014-2025 Taler Systems SA 4 5 TALER is free software; you can redistribute it and/or modify it under the 6 terms of the GNU Affero General Public License as published by the Free Software 7 Foundation; either version 2.1, or (at your option) any later version. 8 9 TALER is distributed in the hope that it will be useful, but WITHOUT ANY 10 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR 11 A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. 12 13 You should have received a copy of the GNU Affero General Public License along with 14 TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> 15 16 @author Marcello Stanisci 17 @author Florian Dold 18 @author Christian Grothoff 19 @author Priscilla Huang 20 @author Martin Schanzenbach 21 22 .. _merchant-api: 23 24 ============================ 25 Merchant Backend RESTful API 26 ============================ 27 28 --------------- 29 Version History 30 --------------- 31 32 The current protocol version is ``v20``. 33 34 Android PoS app is currently targeting ``v20``. 35 36 **Version history:** 37 38 * ``v21`` (in development): Adds self-provisioning and two factor authentication. 39 40 ----------------------- 41 Base URLs and Instances 42 ----------------------- 43 44 A single merchant backend installation can host multiple merchant instances. 45 This is useful when multiple businesses want to share the same payment 46 infrastructure. 47 48 Merchant backends have one special ``admin`` instance. This ``admin`` 49 instance is used when no explicit instance is specified. Note that using 50 ``/instances/admin/$ANYTHING`` is deprecated and will result in a permanent 51 redirect (HTTP status 308) to ``$ANYTHING``. a Despite its name, this instance 52 must be created after the installation. 53 54 Each instance (admin and others) has a base URL. The resources under 55 this base URL are divided into to categories: 56 57 * Public endpoints that are exposed to the Internet 58 * Private endpoints (under ``/private/*``) that are only supposed to be exposed 59 to the merchant internally, and must not be exposed on the 60 Internet. 61 * Management endpoints (under ``/management/*``) are also private and dedicated 62 to CRUD operation over instances and reset authentication settings over all 63 instances. Only accessible with the admin instance authentication token. 64 65 Examples: 66 67 .. code-block:: none 68 69 Base URL of the merchant (admin instance) at merchant-backend.example.com: 70 https://merchant-backend.example.com/ 71 72 A private endpoint (admin instance): 73 https://merchant-backend.example.com/private/orders 74 75 A public endpoint (admin instance and order id "ABCD"): 76 https://merchant-backend.example.com/orders/ABCD 77 78 A private endpoint ("myinst" instance): 79 https://merchant-backend.example.com/instances/myinst/private/orders 80 81 A public endpoint ("myinst" instance and order id "ABCD"): 82 https://merchant-backend.example.com/instances/myinst/orders/ABCD 83 84 A private endpoint (explicit "admin" instance): 85 https://merchant-backend.example.com/private/orders 86 87 A public endpoint (explicit "admin" instance): 88 https://merchant-backend.example.com/orders 89 90 Endpoints to manage other instances (ONLY for implicit "admin" instance): 91 https://merchant-backend.example.com/management/instances 92 https://merchant-backend.example.com/management/instances/$ID 93 94 Endpoints to manage own instance: 95 https://merchant-backend.example.com/private 96 https://merchant-backend.example.com/private/auth 97 https://merchant-backend.example.com/instances/$ID/private 98 https://merchant-backend.example.com/instances/$ID/forgot-password 99 https://merchant-backend.example.com/instances/$ID/private/auth 100 101 Unavailabe endpoints (will return 404): 102 https://merchant-backend.example.com/instances/myinst/private/instances 103 104 ----------------- 105 Generic Responses 106 ----------------- 107 108 The following (error) responses are applicable to all endpoints 109 unless specified otherwise. 110 111 .. http:any:: * 112 113 :http:statuscode:`403 Forbidden`: 114 * ``TALER_EC_GENERIC_FORBIDDEN``: Missing permissions. 115 * ``TALER_EC_MERCHANT_ACCOUNT_TWOFA_UNCONFIRMED``: The account 116 needs to confirm authentication factors before it can proceed 117 with the request. 118 119 -------------- 120 Authentication 121 -------------- 122 123 Each merchant instance has separate authentication settings for the private API resources 124 of that instance. 125 126 Currently, the ``/private/auth/`` API supports two main authentication methods in the ``InstanceAuthConfigurationMessage``: 127 128 * ``external``: (@deprecated since **v20**) With this method, no checks are done by the merchant backend. 129 Instead, a reverse proxy / API gateway must do all authentication/authorization checks. 130 * ``token`` (**@since v19**): With this method, the client must provide an authorization header 131 that contains a bearer token when accessing a protected endpoint in the form 132 ``Authorization: Bearer secret-token:$TOKEN``. 133 ``$TOKEN`` is an authentication token retrieved from the ``/private/token`` endpoint using basic authorization. 134 The respective username is the instance ``$ID``, and the password the instance password (``$INSTANCE_PASSWORD``). 135 A login token is commonly only valid for a limited period of time and scoped to specific permissions. 136 If the ``$INSTANCE_PASSWORD`` is lost, the administrator can set a password 137 using the ``taler-merchant-passwd`` command-line tool. 138 * ``token`` (@deprecated since **v19**): With this method, the client must provide an authentication token in 139 the format ``secret-token: $INSTANCE_PASSWORD``. 140 The behaviour is then equivalent to the ``token`` method above. 141 Any API may be accessed using the bearer authentication ``secret-token: $INSTANCE_PASSWORD``. 142 Notice that this behaviour is deprecated and will be phased out in favor of login tokens. 143 144 For testing, the service may be started with the configuration option ``DISABLED_AUTHENTICATION = YES`` 145 in section ``[merchant]`` (@since **v20**). 146 147 Scopes 148 ^^^^^^ 149 150 Access tokens can be requested with a (limiting) scope. Available scopes and their associated permissions are: 151 152 * ``readonly``: ``*-read`` -- Access to APIs using ``GET`` requests is always allowed. 153 * ``write`` (*deprecated*): See ``all``. 154 * ``all``: ``*`` -- General access to all APIs and endpoints and always refreshable. (@since **v19**) 155 * ``spa``: ``*`` -- General access to all APIs and endpoints. (@since **v20**) 156 * ``order-simple``: ``orders-read``, ``orders-write`` -- Allows the creation of orders and checking of payment status. (@since **v19**) 157 * ``order-pos``: ``orders-read``, ``orders-write``, ``inventory-lock`` -- Same as ``order-simple`` and allows inventory locking. (@since **v19**) 158 * ``order-mgmt``: ``orders-read``, ``orders-write``, ``orders-refund`` -- Same as ``order-simple`` and also allows refunding. (@since **v19**) 159 * ``order-full``: ``orders-read``, ``orders-write``, ``inventory-lock``, ``orders-refund`` -- Same ``order-pos`` and ``order-mgmt`` combined. (@since **v19**) 160 161 Since **v19** the scope may be suffixed with ``:refreshable``, e.g. ``order-pos:refreshable``. 162 This allows the token to be refreshed at the token endpoint. 163 This behaviour replaces the deprecated ``refreshable`` field in the `LoginTokenRequest`. 164 165 ----------------- 166 Configuration API 167 ----------------- 168 169 The configuration API exposes basic information about a merchant backend, 170 such as the implemented version of the protocol and the currency used. 171 172 .. http:get:: /config 173 174 Return the protocol version and currency supported by this merchant backend. 175 This specification corresponds to ``current`` protocol being version **v24**. 176 177 **Response:** 178 179 :http:statuscode:`200 OK`: 180 The body is a `MerchantVersionResponse`. 181 182 **Details:** 183 184 .. ts:def:: MerchantVersionResponse 185 186 interface MerchantVersionResponse { 187 // libtool-style representation of the Merchant protocol version, see 188 // https://www.gnu.org/software/libtool/manual/html_node/Versioning.html#Versioning 189 // The format is "current:revision:age". 190 version: string; 191 192 // Name of the protocol. 193 name: "taler-merchant"; 194 195 // URN of the implementation (needed to interpret 'revision' in version). 196 // @since **v8**, may become mandatory in the future. 197 implementation?: string; 198 199 // Default (!) currency supported by this backend. 200 // This is the currency that the backend should 201 // suggest by default to the user when entering 202 // amounts. See ``currencies`` for a list of 203 // supported currencies and how to render them. 204 currency: string; 205 206 // Which Persona should be used by default by new clients in the SPA. 207 // Can be changed locally per browers under "Personalization". 208 // Possible values include "expert", "offline-vending-machine", 209 // "point-of-sale", "digital-publishing", "e-commerce" and "developer". 210 // @since **v23**. 211 default_persona: string; 212 213 // How services should render currencies supported 214 // by this backend. Maps 215 // currency codes (e.g. "EUR" or "KUDOS") to 216 // the respective currency specification. 217 // All currencies in this map are supported by 218 // the backend. Note that the actual currency 219 // specifications are a *hint* for applications 220 // that would like *advice* on how to render amounts. 221 // Applications *may* ignore the currency specification 222 // if they know how to render currencies that they are 223 // used with. 224 currencies: { currency : CurrencySpecification}; 225 226 // Array of exchanges trusted by the merchant. 227 // @since **v6**. 228 exchanges: ExchangeConfigInfo[]; 229 230 // Set when the merchant supports 231 // self-provisioning instances. 232 // Since protocol **v21** 233 have_self_provisioning: boolean; 234 235 // True if this merchant backend supports the Donau 236 // extension and can thus issue donation receipts. 237 // Should primarily be used to control the SPA's CRUD 238 // functionality for Donau. 239 // @since **v21** 240 have_donau: boolean; 241 242 // Tan channels that are required 243 // to be confirmed for an instance to 244 // be useable. 245 // @since **v21** 246 mandatory_tan_channels?: TanChannel[]; 247 248 // Space-separated list of enabled payment target types. 249 // Useful if the SPA should not show allow adding other 250 // types of bank accounts. "*" is used to represent no 251 // restriction. 252 // @since **v22** 253 payment_target_types: string; 254 255 // Regular expression representing further restrictions 256 // on allowed payment targets. Any "payto://"-URI supplied 257 // for a bank account must match the given regular expression. 258 // For example, "payto://iban/CH.*" would restrict the system 259 // to only Swiss bank accounts. 260 // Optional, no restrictions are imposed if the field is 261 // absent. 262 // @since **v22** 263 // CAUTION: Likely to be removed/deprecated, 264 // as we'll want an array of restrictions with the 265 // same format as the exchange uses, as this allows 266 // proper i18n and spec/code reuse. 267 payment_target_regex? string; 268 269 // Default payment delay for new instances. 270 // This is the default to use for new instances, see the instance value for 271 // the instance-specific default. 272 // A value of "forever" is not allowed. 273 // @since **v22** 274 default_pay_delay: RelativeTime; 275 276 // If the frontend does NOT specify a refund deadline, how long should 277 // refunds be allowed by default? 278 // This is the default to use for new instances, see the instance value for 279 // the instance-specific default. 280 // A value of "forever" is not allowed. 281 // @since **v22** 282 default_refund_delay: RelativeTime; 283 284 // Default wire transfer delay for new instances. 285 // This is the default to use for new instances, see the instance value for 286 // the instance-specific default. 287 // A value of "forever" is not allowed. 288 // @since **v22** 289 default_wire_transfer_delay: RelativeTime; 290 291 // Default interval to which wire deadlines computed by 292 // adding the wire_transfer_delay on top of the refund 293 // deadline should be rounded up to. 294 // @since **v23** 295 default_wire_transfer_rounding_interval: RoundingInterval; 296 } 297 298 .. ts:def:: TanChannel 299 300 enum TanChannel { 301 SMS = "sms", 302 EMAIL = "email" 303 } 304 305 .. ts:def:: RoundingInterval 306 307 enum RoundingInterval { 308 NONE = "NONE", 309 SECOND = "SECOND", 310 MINUTE = "MINUTE", 311 HOUR = "HOUR", 312 DAY = "DAY", 313 WEEK = "WEEK", 314 MONTH = "MONTH", 315 QUARTER = "QUARTER", 316 YEAR = "YEAR" 317 } 318 319 .. ts:def:: ExchangeConfigInfo 320 321 interface ExchangeConfigInfo { 322 323 // Base URL of the exchange REST API. 324 base_url: string; 325 326 // Currency for which the merchant is configured 327 // to trust the exchange. 328 // May not be the one the exchange actually uses, 329 // but is the only one we would trust this exchange for. 330 currency: string; 331 332 // Offline master public key of the exchange. The 333 // ``/keys`` data must be signed with this public 334 // key for us to trust it. 335 master_pub: EddsaPublicKey; 336 } 337 338 .. include:: tos.rst 339 340 --------------- 341 Two Factor Auth 342 --------------- 343 344 202 Challenge Responses 345 ^^^^^^^^^^^^^^^^^^^^^^^ 346 347 Various APIs generate ``202 Accepted`` HTTP status codes when multi-factor 348 authentication (MFA) is required. In this case, the response will be a 349 `ChallengeResponse`. In these cases, the client must first request and solve 350 one or more challenges before repeating the request. When repeating the 351 request, they must include a list of comma-separated challenge IDs of the 352 solved challenges in an ``Taler-Challenge-Ids`` HTTP header. The body must 353 remain absolutely unchanged. 354 355 .. note:: 356 357 If all allowed attempts to solve the MFA challenge(s) fail, the endpoint 358 may start to return ``403 Forbidden`` until the issued challenges expire, 359 preventing the request from being completed for a while. In this case, 360 repeating the request with a different body may still be allowed! 361 362 .. ts:def:: ChallengeResponse 363 364 // @since v21 365 interface ChallengeResponse { 366 // List of challenge IDs that must be solved before the 367 // client may proceed. 368 challenges: Challenge[]; 369 370 // True if **all** challenges must be solved (AND), false if 371 // it is sufficient to solve one of them (OR). 372 combi_and: boolean; 373 374 } 375 376 .. ts:def:: Challenge 377 378 interface Challenge { 379 // Unique identifier of the challenge to solve to run this protected 380 // operation. 381 challenge_id: string; 382 383 // Channel of the last successful transmission of the TAN challenge. 384 tan_channel: TanChannel; 385 386 // Info of the last successful transmission of the TAN challenge. 387 // Hint to show to the user as to where the challenge was 388 // sent or what to use to solve the challenge. May not 389 // contain the full address for privacy. 390 tan_info: string; 391 392 } 393 394 Requesting challenges 395 ^^^^^^^^^^^^^^^^^^^^^ 396 397 .. http:post:: [/instances/$INSTANCE]/challenge/$CHALLENGE_ID 398 399 Send TAN code for the ``CHALLENGE_ID`` challenge. 400 401 This request can be posted several times to trigger TAN retransmission when 402 the current code has expired or too many confirmation attempts have been 403 made. 404 405 This endpoint is not authenticated, it may be used even when mandatory TAN 406 channels were not validated yet. 407 408 @since **v21** 409 410 **Request:** 411 412 The request body must be a JSON object, but can otherwise be empty 413 (so just send '{}'). 414 415 **Response:** 416 417 :http:statuscode:`200 Ok`: 418 The TAN code has been sent. The body will be a `ChallengeRequestResponse`. 419 :http:statuscode:`404 Not Found`: 420 The challenge was not found. 421 Returned with ``TALER_EC_MERCHANT_TAN_CHALLENGE_UNKNOWN``. 422 :http:statuscode:`410 Gone`: 423 The challenge was already solved. 424 Returned with ``TALER_EC_MERCHANT_TAN_CHALLENGE_SOLVED``. 425 :http:statuscode:`429 Too many requests`: 426 Too many challenges are active right now, 427 you must wait or confirm current challenges. 428 Returned with ``TALER_EC_MERCHANT_TAN_TOO_EARLY``. 429 :http:statuscode:`502 Bad Gateway`: 430 TAN transmition via ``tan_channel`` failed. 431 Returned with ``TALER_EC_MERCHANT_MFA_HELPER_EXEC_FAILED``. 432 433 **Details:** 434 435 .. ts:def:: ChallengeRequestResponse 436 437 interface ChallengeRequestResponse { 438 // How long does the client have to solve the 439 // challenge. 440 solve_expiration: Timestamp; 441 442 // What is the earlist time at which the client 443 // may request a new challenge to be transmitted? 444 earliest_retransmission: Timestamp; 445 } 446 447 Solving challenges 448 ^^^^^^^^^^^^^^^^^^ 449 450 .. http:post:: [/instances/$INSTANCE]/challenge/$CHALLENGE_ID/confirm 451 452 Solves the ``CHALLENGE_ID`` challenge and allows performing the protected operation. 453 454 @since **v21** 455 456 When the challenge is confirmed, you can call the protected endpoint again 457 with ``CHALLENGE_ID`` in the ``Taler-Challenge-Ids`` HTTP header and the 458 original request body. 459 460 This endpoints is not authenticated for token creation challenges. Too many 461 unsuccessful attempts to confirm token creation challenges block the 462 account. 463 464 This endpoint may be used even when mandatory TAN channels 465 were not validated yet. 466 467 **Request:** 468 469 .. ts:def:: MerchantChallengeSolveRequest 470 471 interface MerchantChallengeSolveRequest { 472 473 // The TAN code that solves $CHALLENGE_ID. 474 tan: string; 475 } 476 477 **Response:** 478 479 :http:statuscode:`204 No Content`: 480 The challenge was solved. 481 :http:statuscode:`404 Not Found`: 482 The challenge was not found. 483 Returned with ``TALER_EC_MERCHANT_TAN_CHALLENGE_UNKNOWN``. 484 :http:statuscode:`409 Conflict`: 485 Wrong TAN, returned with an 486 error code of ``TALER_EC_MERCHANT_TAN_CHALLENGE_FAILED``. 487 :http:statuscode:`429 Too many requests`: 488 Too many failed confirmation attempts, a new TAN must be requested. 489 Returned with ``TALER_EC_MERCHANT_TAN_TOO_MANY_ATTEMPTS``. 490 491 ---------- 492 Wallet API 493 ---------- 494 495 This section describes (public) endpoints that wallets must be able 496 to interact with directly (without HTTP-based authentication). These 497 endpoints are used to process payments (claiming an order, paying 498 for the order, checking payment/refund status and aborting payments), 499 and to process refunds (checking refund status, obtaining the refund). 500 501 502 Claiming an order 503 ^^^^^^^^^^^^^^^^^ 504 505 The first step of processing any Taler payment consists of the 506 (authorized) wallet claiming the order for itself. In this process, 507 the wallet provides a wallet-generated nonce that is added 508 into the contract terms. This step prevents two different 509 wallets from paying for the same contract, which would be bad 510 especially if the merchant only has finite stocks. 511 512 A claim token can be used to ensure that the wallet claiming an 513 order is actually authorized to do so. This is useful in cases 514 where order IDs are predictable and malicious actors may try to 515 claim orders (say in a case where stocks are limited). 516 517 518 .. http:post:: [/instances/$INSTANCE]/orders/$ORDER_ID/claim 519 520 Wallet claims ownership (via nonce) over an order. By claiming 521 an order, the wallet obtains the full contract terms, and thereby 522 implicitly also the hash of the contract terms it needs for the 523 other ``public`` APIs to authenticate itself as the wallet that 524 is indeed eligible to inspect this particular order's status. 525 526 **Request:** 527 528 The request must be a `ClaimRequest`. 529 530 **Response:** 531 532 :http:statuscode:`200 OK`: 533 The client has successfully claimed the order. 534 The response contains the :ref:`contract terms <contract-terms>`. 535 :http:statuscode:`404 Not found`: 536 The backend is unaware of the instance or order. 537 :http:statuscode:`409 Conflict`: 538 Someone else has already claimed the same order ID with a different nonce. 539 540 **Details:** 541 542 .. ts:def:: ClaimRequest 543 544 interface ClaimRequest { 545 // Nonce to identify the wallet that claimed the order. 546 nonce: string; 547 548 // Token that authorizes the wallet to claim the order. 549 // *Optional* as the merchant may not have required it 550 // (``create_token`` set to ``false`` in `PostOrderRequest`). 551 token?: ClaimToken; 552 } 553 554 .. ts:def:: ClaimResponse 555 556 interface ClaimResponse { 557 // Contract terms of the claimed order 558 contract_terms: ContractTerms; 559 560 // Signature by the merchant over the contract terms. 561 sig: EddsaSignature; 562 } 563 564 Making the payment 565 ^^^^^^^^^^^^^^^^^^ 566 567 .. http:post:: [/instances/$INSTANCE]/orders/$ORDER_ID/pay 568 569 Pay for an order by giving a deposit permission for coins. Typically used by 570 the customer's wallet. Note that this request does not include the 571 usual ``h_contract`` argument to authenticate the wallet, as the hash of 572 the contract is implied by the signatures of the coins. Furthermore, this 573 API doesn't really return useful information about the order. 574 575 **Request:** 576 577 The request must be a `pay request <PayRequest>`. 578 579 **Response:** 580 581 :http:statuscode:`200 OK`: 582 The exchange accepted all of the coins. 583 The body is a `payment response <PaymentResponse>`. 584 The ``frontend`` should now fulfill the contract. 585 Note that it is possible that refunds have been granted. 586 :http:statuscode:`400 Bad request`: 587 Either the client request is malformed or some specific processing error 588 happened that may be the fault of the client as detailed in the JSON body 589 of the response. 590 This includes the case where the payment is insufficient (sum is below 591 the required total amount, for example because the wallet calculated the 592 fees wrong). 593 594 Applicable error codes: 595 596 * ``MERCHANT_POST_ORDERS_ID_PAY_DENOMINATION_KEY_NOT_FOUND``: Wallet tried 597 to pay with a non-existent denomination. 598 599 :http:statuscode:`402 Payment required`: 600 There used to be a sufficient payment, but due to refunds the amount effectively 601 paid is no longer sufficient. (If the amount is generally insufficient, we 602 return "400 Bad Request", only if this is because of refunds we return 402.) 603 :http:statuscode:`403 Forbidden`: 604 One of the coin signatures was not valid. 605 :http:statuscode:`404 Not found`: 606 The merchant backend could not find the order or the instance and thus cannot process the payment. 607 :http:statuscode:`408 Request timeout`: 608 The backend took too long to process the request. Likely the merchant's connection 609 to the exchange timed out. Try again. 610 :http:statuscode:`409 Conflict`: 611 The exchange rejected the payment because a coin was already spent (or 612 used in a different way for the same purchase previously), or 613 the merchant rejected the payment because the order was already fully paid 614 (and then return signatures with refunds). If a coin was already spent 615 (this includes re-using the same coin after a refund), 616 the response will include the ``exchange_url`` for which the payment failed, 617 in addition to the response from the exchange to the ``/batch-deposit`` request. 618 619 Applicable error codes: 620 621 * ``MERCHANT_POST_ORDERS_ID_PAY_INSUFFICIENT_FUNDS``: Exchange reported insufficient 622 funds for one of the coins. 623 624 :http:statuscode:`410 Gone`: 625 The offer has expired and is no longer available. 626 :http:statuscode:`412 Precondition failed`: 627 The given exchange is not acceptable for this merchant, as it is not in the 628 list of accepted exchanges and not audited by an approved auditor. 629 TODO: Status code may be changed to 409 in the future as 412 is technically wrong. 630 :http:statuscode:`451 Unavailable for Legal Reasons`: 631 The exchange has rejected the deposit by the merchant 632 for legal reasons. This is **not** exactly a client 633 failure (and possibly nobody's fault except for the 634 regulator). In any case, the wallet should refresh 635 the deposited coins of the affected exchange and 636 may try to pay with coins from another exchange if 637 possible (it has such coins and the merchant accepts 638 coins from another exchange). 639 The body is a `PaymentDeniedLegallyResponse` with 640 details about the failure. 641 Since protocol **v17**. 642 :http:statuscode:`502 Bad gateway`: 643 The merchant's interaction with the exchange failed in some way. 644 The client might want to try again later. 645 This includes failures such as the denomination key of a coin not being 646 known to the exchange as far as the merchant can tell. 647 :http:statuscode:`504 Gateway timeout`: 648 The merchant's interaction with the exchange took too long. 649 The client might want to try again later. 650 651 The backend will return verbatim the error codes received from the exchange's 652 :ref:`deposit <deposit>` API. If the wallet made a mistake, like by 653 double-spending for example, the frontend should pass the reply verbatim to 654 the browser/wallet. If the payment was successful, the frontend MAY use 655 this to trigger some business logic. 656 657 **Details:** 658 659 .. ts:def:: PaymentResponse 660 661 interface PaymentResponse { 662 // Signature on ``TALER_PaymentResponsePS`` with the public 663 // key of the merchant instance. 664 sig: EddsaSignature; 665 666 // Text to be shown to the point-of-sale staff as a proof of 667 // payment. 668 pos_confirmation?: string; 669 670 // Signed tokens. Returned in the same order as the 671 // token envelopes were provided in the request. Specifically, 672 // the order will follow the order of the outputs from the 673 // contract terms, and then within each output follow the 674 // order in which the ``wallet_data`` contained the respective 675 // blinded envelopes. The donation tokens will be present 676 // at the offset matching the place where a donation receipt 677 // was indicated in the outputs array, and of course be skipped 678 // if the ``PayWalletData`` did not have a ``donau`` field. 679 // @since protocol **v21** 680 token_sigs?: SignedTokenEnvelope[]; 681 682 } 683 684 .. ts:def:: PayRequest 685 686 interface PayRequest { 687 // The coins used to make the payment. 688 coins: CoinPaySig[]; 689 690 // Input tokens required by choice indicated by ``choice_index``. 691 // @since protocol **v21** 692 tokens?: TokenUseSig[]; 693 694 // Custom inputs from the wallet for the contract. 695 wallet_data?: PayWalletData; 696 697 // The session for which the payment is made (or replayed). 698 // Only set for session-based payments. 699 session_id?: string; 700 701 } 702 703 .. ts:def:: SignedTokenEnvelope 704 705 interface SignedTokenEnvelope { 706 707 // Blind signature made by the merchant. 708 blind_sig: TokenIssueBlindSig; 709 710 } 711 712 .. ts:def:: TokenIssueBlindSig 713 714 type TokenIssueBlindSig = RSATokenIssueBlindSig | CSTokenIssueBlindSig; 715 716 .. ts:def:: RSATokenIssueBlindSig 717 718 interface RSATokenIssueBlindSig { 719 cipher: "RSA"; 720 721 // (blinded) RSA signature 722 blinded_rsa_signature: BlindedRsaSignature; 723 } 724 725 .. ts:def:: CSTokenIssueBlindSig 726 727 interface CSTokenIssueBlindSig { 728 cipher: "CS"; 729 730 // Signer chosen bit value, 0 or 1, used 731 // in Clause Blind Schnorr to make the 732 // ROS problem harder. 733 b: Integer; 734 735 // Blinded scalar calculated from c_b. 736 s: Cs25519Scalar; 737 738 } 739 740 .. ts:def:: PayWalletData 741 742 interface PayWalletData { 743 // Index of the selected choice within the ``choices`` array of 744 // the contract terms. 745 // @since protocol **v21** 746 choice_index?: Integer; 747 748 // Array of output tokens to be (blindly) signed by the merchant. 749 // Output tokens specified in choice indicated by ``choice_index``. 750 // @since protocol **v21** 751 tokens_evs?: TokenEnvelope[]; 752 753 // Request for donation receipts to be issued. 754 // @since protocol **v21** 755 donau?: DonationRequestData; 756 } 757 758 .. ts:def:: DonationRequestData 759 760 interface DonationRequestData { 761 // Base URL of the selected Donau 762 url: string; 763 764 // Year for which the donation receipts are expected. 765 // Also determines which keys are used to sign the 766 // blinded donation receipts. 767 year: Integer; 768 769 // Array of blinded donation receipts to sign. 770 // Must NOT be empty (if no donation receipts 771 // are desired, just leave the entire ``donau`` 772 // argument blank). 773 budikeypairs: BlindedDonationReceiptKeyPair[]; 774 } 775 776 .. ts:def:: CoinPaySig 777 778 interface CoinPaySig { 779 // Signature by the coin. 780 coin_sig: EddsaSignature; 781 782 // Public key of the coin being spent. 783 coin_pub: EddsaPublicKey; 784 785 // Signature made by the denomination public key. 786 ub_sig: UnblindedSignature; 787 788 // The hash of the denomination public key associated with this coin. 789 h_denom: HashCode; 790 791 // The amount that is subtracted from this coin with this payment. 792 contribution: Amount; 793 794 // URL of the exchange this coin was withdrawn from. 795 exchange_url: string; 796 797 // Signature affirming the posession of the 798 // respective private key proving that the payer 799 // is old enough. Only provided if the paid contract 800 // has an age restriction and the coin is 801 // age-restricted. 802 minimum_age_sig?: EddsaSignature; 803 804 // Age commitment vector of the coin. 805 // Only provided if the paid contract 806 // has an age restriction and the coin is 807 // age-restricted. 808 age_commitment?: Edx25519PublicKey[]; 809 810 // Hash over the agge commitment vector of the coin. 811 // Only provided if the paid contract 812 // does NOT have an age restriction and the coin is 813 // age-restricted. 814 h_age_commitment?: AgeCommitmentHash; 815 } 816 817 .. ts:def:: TokenUseSig 818 819 interface TokenUseSig { 820 821 // Signature on ``TALER_TokenUseRequestPS`` with the token use key of 822 // the token being used in this request. 823 token_sig: EddsaSignature; 824 825 // Token use public key. 826 token_pub: EddsaPublicKey; 827 828 // Unblinded signature on ``TALER_TokenIssueRequestPS`` with the token 829 // issue public key of the merchant. 830 ub_sig: UnblindedSignature; 831 832 // Hash of the token issue public key associated with this token. 833 h_issue: HashCode; 834 } 835 836 .. ts:def:: TokenEnvelope 837 838 // This type depends on the cipher used to sign token families. This is 839 // configured by the merchant and defined for each token family in the 840 // contract terms. 841 type TokenEnvelope = RSATokenEnvelope | CSTokenEnvelope; 842 843 .. ts:def:: RSATokenEnvelope 844 845 interface RSATokenEnvelope { 846 847 // RSA is used for the blind signature. 848 cipher: "RSA"; 849 850 // Blinded signature of the token's `public EdDSA key <eddsa-token-pub>`. 851 rsa_blinded_pub: BlindedRsaSignature; 852 853 } 854 855 .. ts:def:: CSTokenEnvelope 856 857 interface CSTokenEnvelope { 858 // Blind Clause-Schnorr signature scheme is used for the blind signature. 859 // See https://taler.net/papers/cs-thesis.pdf for details. 860 cipher: "CS"; 861 862 // Public nonce 863 cs_nonce: string; // Crockford `Base32` encoded 864 865 // Two Curve25519 scalars, each representing a blinded challenge 866 cs_blinded_c0: string; // Crockford `Base32` encoded 867 cs_blinded_c1: string; // Crockford `Base32` encoded 868 } 869 870 .. ts:def:: PaymentDeniedLegallyResponse 871 872 interface PaymentDeniedLegallyResponse { 873 874 // Base URL of the exchanges that denied the payment. 875 // The wallet should refresh the coins from these 876 // exchanges, but may try to pay with coins from 877 // other exchanges. 878 exchange_base_urls: string[]; 879 880 } 881 882 883 Querying payment status 884 ^^^^^^^^^^^^^^^^^^^^^^^ 885 886 .. http:get:: [/instances/$INSTANCE]/orders/$ORDER_ID 887 888 Query the payment status of an order. This endpoint is for the wallet 889 and possibly for Web shops and other integrations that need an 890 unauthenticated way to query the order status (like when checking 891 it from JavaScript from inside the customer's browser). It is also 892 possible to just redirect a browser to this URL to initiate the 893 payment process. 894 895 When a client (usually a wallet) goes to this URL and it is unpaid, 896 it will be prompted for payment. 897 This endpoint typically also supports requests with the "Accept" header 898 requesting "text/html". In this case, an HTML response suitable for 899 triggering the interaction with the wallet is returned, with ``timeout_ms`` 900 ignored (treated as zero). If the backend installation does not include the 901 required HTML templates, a 406 status code is returned. 902 903 In the case that the request was made with a claim token (even the wrong one) 904 and the order was claimed and paid, the server will redirect the client to 905 the fulfillment URL. This redirection will happen with a 302 status code 906 if the "Accept" header specified "text/html", and with a 202 status code 907 otherwise. 908 909 **Request:** 910 911 :query h_contract=HASH: *Optional*. Hash of the order's contract terms (this is used to authenticate the wallet/customer in case $ORDER_ID is guessable). Required once an order was claimed. 912 :query token=TOKEN: *Optional*. Authorizes the request via the claim token that was returned in the `PostOrderResponse`. Used with unclaimed orders only. Whether token authorization is required is determined by the merchant when the frontend creates the order. 913 :query session_id=STRING: *Optional*. Session ID that the payment must be bound to. If not specified, the payment is not session-bound. 914 :query timeout_ms=NUMBER: *Optional.* If specified, the merchant backend will 915 wait up to ``timeout_ms`` milliseconds for completion of the payment before 916 sending the HTTP response. A client must never rely on this behavior, as the 917 merchant backend may return a response immediately. 918 :query await_refund_obtained=BOOLEAN: *Optional*. If set to "yes", poll for the order's pending refunds to be picked up. ``timeout_ms`` specifies how long we will wait for the refund. 919 :query refund=AMOUNT: *Optional*. Indicates that we are polling for a refund above the given AMOUNT. ``timeout_ms`` will specify how long we will wait for the refund. 920 :query allow_refunded_for_repurchase: *Optional*. Since protocol **v9** refunded orders are only returned under "already_paid_order_id" if this flag is set explicitly to "YES". 921 922 **Response:** 923 924 :http:statuscode:`200 OK`: 925 The response is a `StatusPaidResponse`. 926 :http:statuscode:`202 Accepted`: 927 The response is a `StatusGotoResponse`. Only returned if the content type requested was not HTML. 928 The target site may allow the client to setup a fresh order (as this one has been taken) or may 929 trigger repurchase detection. 930 :http:statuscode:`302 Found`: 931 The client should go to the indicated location (via HTTP "Location:" header). 932 Only returned if the content type requested was HTML. 933 The target site may allow the client to setup a fresh order (as this one has been taken) or may 934 trigger repurchase detection. 935 :http:statuscode:`402 Payment required`: 936 The response is a `StatusUnpaidResponse`. 937 :http:statuscode:`403 Forbidden`: 938 The ``h_contract`` (or the ``token`` for unclaimed orders) does not match the order 939 and we have no fulfillment URL in the contract. 940 :http:statuscode:`404 Not found`: 941 The merchant backend is unaware of the order. 942 :http:statuscode:`406 Not acceptable`: 943 The merchant backend could not load the template required to generate a reply in the desired format. (Likely HTML templates were not properly installed.) 944 945 **Details:** 946 947 .. ts:def:: StatusPaidResponse 948 949 interface StatusPaidResponse { 950 // Was the payment refunded (even partially, via refund or abort)? 951 refunded: boolean; 952 953 // Is any amount of the refund still waiting to be picked up (even partially)? 954 refund_pending: boolean; 955 956 // Amount that was refunded in total. 957 refund_amount: Amount; 958 959 // Amount that already taken by the wallet. 960 refund_taken: Amount; 961 } 962 963 .. ts:def:: StatusGotoResponse 964 965 interface StatusGotoResponse { 966 // The client should go to the reorder URL, there a fresh 967 // order might be created as this one is taken by another 968 // customer or wallet (or repurchase detection logic may 969 // apply). 970 public_reorder_url: string; 971 } 972 973 .. ts:def:: StatusUnpaidResponse 974 975 interface StatusUnpaidResponse { 976 // URI that the wallet must process to complete the payment. 977 taler_pay_uri: string; 978 979 // Fulfillment URL of the contract. 980 // If present, it should be possible to create an 981 // equivalent order by redirecting a browser to this 982 // URL. Once the customer has paid, they should see the 983 // order's fulfillment (digital goods, tracking data for 984 // shipping, etc.) under this URL (assuming they use the 985 // same session that the wallet used when making the payment). 986 fulfillment_url?: string; 987 988 // Alternative order ID which was paid for already in the same session. 989 // Only given if the same product was purchased before in the same session. 990 already_paid_order_id?: string; 991 } 992 993 994 995 Demonstrating payment 996 ^^^^^^^^^^^^^^^^^^^^^ 997 998 In case a wallet has already paid for an order, this is a fast way of proving 999 to the merchant that the order was already paid. The alternative would be to 1000 replay the original payment, but simply providing the merchant's signature 1001 saves bandwidth and computation time. 1002 1003 Demonstrating payment is useful in case a digital good was made available 1004 only to clients with a particular session ID: if that session ID expired or 1005 if the user is using a different client, demonstrating payment will allow 1006 the user to regain access to the digital good without having to pay for it 1007 again. 1008 1009 .. http:post:: [/instances/$INSTANCE]/orders/$ORDER_ID/paid 1010 1011 Prove that the client previously paid for an order by providing 1012 the merchant's signature from the `payment response <PaymentResponse>`. 1013 Typically used by the customer's wallet if it receives a request for 1014 payment for an order that it already paid. This is more compact than 1015 re-transmitting the full payment details. 1016 Note that this request does include the 1017 usual ``h_contract`` argument to authenticate the wallet and 1018 to allow the merchant to verify the signature before checking 1019 with its own database. 1020 1021 **Request:** 1022 1023 The request must be a `paid request <PaidRequest>`. 1024 1025 **Response:** 1026 1027 :http:statuscode:`200 Ok`: 1028 The merchant accepted the signature. 1029 The ``frontend`` should now fulfill the contract. 1030 Note that it is possible that refunds have been granted. Response is of type `PaidRefundStatusResponse`. 1031 :http:statuscode:`400 Bad request`: 1032 Either the client request is malformed or some specific processing error 1033 happened that may be the fault of the client as detailed in the JSON body 1034 of the response. 1035 :http:statuscode:`403 Forbidden`: 1036 The signature was not valid. 1037 :http:statuscode:`404 Not found`: 1038 The merchant backend could not find the order or the instance 1039 and thus cannot process the request. 1040 1041 **Details**: 1042 1043 .. ts:def:: PaidRefundStatusResponse 1044 1045 interface PaidRefundStatusResponse { 1046 1047 // Text to be shown to the point-of-sale staff as a proof of 1048 // payment (present only if re-usable OTP algorithm is used). 1049 pos_confirmation?: string; 1050 1051 // True if the order has been subjected to 1052 // refunds. False if it was simply paid. 1053 refunded: boolean; 1054 } 1055 1056 .. ts:def:: PaidRequest 1057 1058 interface PaidRequest { 1059 // Signature on ``TALER_PaymentResponsePS`` with the public 1060 // key of the merchant instance. 1061 sig: EddsaSignature; 1062 1063 // Hash of the order's contract terms (this is used to authenticate the 1064 // wallet/customer and to enable signature verification without 1065 // database access). 1066 h_contract: HashCode; 1067 1068 // Session id for which the payment is proven. 1069 session_id: string; 1070 } 1071 1072 1073 Aborting incomplete payments 1074 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 1075 1076 In rare cases (such as a wallet restoring from an outdated backup) it is possible 1077 that a wallet fails to complete a payment because it runs out of e-cash in the 1078 middle of the process. The abort API allows the wallet to abort the payment for 1079 such an incomplete payment and to regain control over the coins that were spent 1080 so far. Aborts are not permitted for payments that have completed. In contrast to 1081 refunds, aborts do not require approval by the merchant because aborts always 1082 are for incomplete payments for an order and never for established contracts. 1083 1084 1085 .. _order-abort: 1086 .. http:post:: [/instances/$INSTANCE]/orders/$ORDER_ID/abort 1087 1088 Abort paying for an order and obtain a refund for coins that 1089 were already deposited as part of a failed payment. 1090 1091 **Request:** 1092 1093 The request must be an `abort request <AbortRequest>`. We force the wallet 1094 to specify the affected coins as it may only request for a subset of the coins 1095 (i.e. because the wallet knows that some were double-spent causing the failure). 1096 Also we need to know the coins because there may be two wallets "competing" over 1097 the same order and one wants to abort while the other still proceeds with the 1098 payment. Here we need to again know which subset of the deposits to abort. 1099 1100 **Response:** 1101 1102 :http:statuscode:`200 OK`: 1103 The merchant accepted the request, and passed it on to the exchange. The body is a 1104 a `abort response <AbortResponse>`. Note that the exchange 1105 MAY still have encountered errors in processing. Those will then be part of 1106 the body. Wallets MUST carefully consider errors for each of the coins as 1107 returned by the exchange. 1108 :http:statuscode:`400 Bad request`: 1109 Either the client request is malformed or some specific processing error 1110 happened that may be the fault of the client as detailed in the JSON body 1111 of the response. 1112 :http:statuscode:`403 Forbidden`: 1113 The ``h_contract`` does not match the $ORDER_ID. 1114 :http:statuscode:`404 Not found`: 1115 The merchant backend could not find the order or the instance 1116 and thus cannot process the abort request. 1117 :http:statuscode:`408 Request timeout`: 1118 The merchant backend took too long getting a response from the exchange. 1119 The wallet SHOULD retry soon. 1120 :http:statuscode:`412 Precondition failed`: 1121 Aborting the payment is not allowed, as the original payment did succeed. 1122 It is possible that a different wallet succeeded with the payment. This 1123 wallet should thus try to refresh all of the coins involved in the payment. 1124 :http:statuscode:`502 Bad gateway`: 1125 The merchant's interaction with the exchange failed in some way. 1126 The error from the exchange is included. 1127 :http:statuscode:`504 Gateway timeout`: 1128 The merchant's interaction with the exchange took too long. 1129 The client might want to try again later. 1130 1131 The backend will return an `abort response <AbortResponse>`, which includes 1132 verbatim the error codes received from the exchange's 1133 :ref:`refund <exchange_refund>` API. The frontend should pass the replies verbatim to 1134 the browser/wallet. 1135 1136 **Details:** 1137 1138 .. ts:def:: AbortRequest 1139 1140 interface AbortRequest { 1141 1142 // Hash of the order's contract terms (this is used to authenticate the 1143 // wallet/customer in case $ORDER_ID is guessable). 1144 h_contract: HashCode; 1145 1146 // List of coins the wallet would like to see refunds for. 1147 // (Should be limited to the coins for which the original 1148 // payment succeeded, as far as the wallet knows.) 1149 coins: AbortingCoin[]; 1150 } 1151 1152 .. ts:def:: AbortingCoin 1153 1154 interface AbortingCoin { 1155 // Public key of a coin for which the wallet is requesting an abort-related refund. 1156 coin_pub: EddsaPublicKey; 1157 1158 // The amount to be refunded (matches the original contribution) 1159 // @Deprecated since **v18**. 1160 contribution: Amount; 1161 1162 // URL of the exchange this coin was withdrawn from. 1163 exchange_url: string; 1164 } 1165 1166 1167 .. ts:def:: AbortResponse 1168 1169 interface AbortResponse { 1170 1171 // List of refund responses about the coins that the wallet 1172 // requested an abort for. In the same order as the ``coins`` 1173 // from the original request. 1174 // The ``rtransaction_id`` is implied to be 0. 1175 refunds: MerchantAbortPayRefundStatus[]; 1176 } 1177 1178 .. ts:def:: MerchantAbortPayRefundStatus 1179 1180 type MerchantAbortPayRefundStatus = 1181 | MerchantAbortPayRefundSuccessStatus 1182 | MerchantAbortPayRefundUndepositedStatus 1183 | MerchantAbortPayRefundFailureStatus; 1184 1185 .. ts:def:: MerchantAbortPayRefundFailureStatus 1186 1187 // Details about why a refund failed. 1188 interface MerchantAbortPayRefundFailureStatus { 1189 // Used as tag for the sum type RefundStatus sum type. 1190 type: "failure"; 1191 1192 // HTTP status of the exchange request, must NOT be 200. 1193 exchange_status: Integer; 1194 1195 // Taler error code from the exchange reply, if available. 1196 exchange_code?: Integer; 1197 1198 // If available, HTTP reply from the exchange. 1199 exchange_reply?: Object; 1200 } 1201 1202 .. ts:def:: MerchantAbortPayRefundSuccessStatus 1203 1204 // Additional details needed to verify the refund confirmation signature 1205 // (``h_contract_terms`` and ``merchant_pub``) are already known 1206 // to the wallet and thus not included. 1207 interface MerchantAbortPayRefundSuccessStatus { 1208 // Used as tag for the sum type MerchantCoinRefundStatus sum type. 1209 type: "success"; 1210 1211 // HTTP status of the exchange request, 200 (integer) required for refund confirmations. 1212 exchange_status: 200; 1213 1214 // The EdDSA :ref:`signature` (binary-only) with purpose 1215 // `TALER_SIGNATURE_EXCHANGE_CONFIRM_REFUND` using a current signing key of the 1216 // exchange affirming the successful refund. 1217 exchange_sig: EddsaSignature; 1218 1219 // Public EdDSA key of the exchange that was used to generate the signature. 1220 // Should match one of the exchange's signing keys from ``/keys``. It is given 1221 // explicitly as the client might otherwise be confused by clock skew as to 1222 // which signing key was used. 1223 exchange_pub: EddsaPublicKey; 1224 } 1225 1226 .. ts:def:: MerchantAbortPayRefundUndepositedStatus 1227 1228 // The merchant didn't deposit the coin in the first place, 1229 // no refund possible. 1230 interface MerchantAbortPayRefundSuccessStatus { 1231 // Used as tag for the sum type MerchantCoinRefundStatus sum type. 1232 type: "undeposited"; 1233 } 1234 1235 1236 Obtaining refunds 1237 ^^^^^^^^^^^^^^^^^ 1238 1239 Refunds allow merchants to fully or partially restitute e-cash to a wallet, 1240 for example because the merchant determined that it could not actually fulfill 1241 the contract. Refunds must be approved by the merchant's business logic. 1242 1243 1244 .. http:post:: [/instances/$INSTANCE]/orders/$ORDER_ID/refund 1245 1246 Obtain refunds for an order. After talking to the exchange, the refunds will 1247 no longer be pending if processed successfully. 1248 1249 **Request:** 1250 1251 The request body is a `WalletRefundRequest` object. 1252 1253 **Response:** 1254 1255 :http:statuscode:`200 OK`: 1256 The response is a `WalletRefundResponse`. 1257 :http:statuscode:`204 No content`: 1258 There are no refunds for the order. 1259 :http:statuscode:`403 Forbidden`: 1260 The ``h_contract`` does not match the order. 1261 :http:statuscode:`404 Not found`: 1262 The merchant backend is unaware of the order. 1263 :http:statuscode:`410 Gone`: 1264 The wire deadline has past and it is too late to grant a refund. 1265 Since protocol **v24**. 1266 :http:statuscode:`451 Unavailable for Legal Reasons`: 1267 The refund could not be awarded because of legal 1268 reasons (an exchange refused). The wallet should 1269 show an error message and suggest to the user to 1270 get in touch with the merchant to try to get the 1271 refund in a different way. 1272 The body is a `PaymentDeniedLegallyResponse` with 1273 details about the exchange causing the failure. 1274 Since protocol **v17**. 1275 1276 **Details:** 1277 1278 .. ts:def:: WalletRefundRequest 1279 1280 interface WalletRefundRequest { 1281 // Hash of the order's contract terms (this is used to authenticate the 1282 // wallet/customer). 1283 h_contract: HashCode; 1284 } 1285 1286 .. ts:def:: WalletRefundResponse 1287 1288 interface WalletRefundResponse { 1289 // Amount that was refunded in total. 1290 refund_amount: Amount; 1291 1292 // Successful refunds for this payment, empty array for none. 1293 refunds: MerchantCoinRefundStatus[]; 1294 1295 // Public key of the merchant. 1296 merchant_pub: EddsaPublicKey; 1297 1298 } 1299 1300 .. ts:def:: MerchantCoinRefundStatus 1301 1302 type MerchantCoinRefundStatus = 1303 | MerchantCoinRefundSuccessStatus 1304 | MerchantCoinRefundFailureStatus; 1305 1306 .. ts:def:: MerchantCoinRefundFailureStatus 1307 1308 // Details about why a refund failed. 1309 interface MerchantCoinRefundFailureStatus { 1310 // Used as tag for the sum type RefundStatus sum type. 1311 type: "failure"; 1312 1313 // HTTP status of the exchange request, must NOT be 200. 1314 exchange_status: Integer; 1315 1316 // Taler error code from the exchange reply, if available. 1317 exchange_code?: Integer; 1318 1319 // If available, HTTP reply from the exchange. 1320 exchange_reply?: Object; 1321 1322 // Refund transaction ID. 1323 rtransaction_id: Integer; 1324 1325 // Public key of a coin that was refunded. 1326 coin_pub: EddsaPublicKey; 1327 1328 // Amount that was refunded, including refund fee charged by the exchange 1329 // to the customer. 1330 refund_amount: Amount; 1331 1332 // Timestamp when the merchant approved the refund. 1333 // Useful for grouping refunds. 1334 execution_time: Timestamp; 1335 } 1336 1337 .. ts:def:: MerchantCoinRefundSuccessStatus 1338 1339 // Additional details needed to verify the refund confirmation signature 1340 // (``h_contract_terms`` and ``merchant_pub``) are already known 1341 // to the wallet and thus not included. 1342 interface MerchantCoinRefundSuccessStatus { 1343 // Used as tag for the sum type MerchantCoinRefundStatus sum type. 1344 type: "success"; 1345 1346 // HTTP status of the exchange request, 200 (integer) required for refund confirmations. 1347 exchange_status: 200; 1348 1349 // The EdDSA :ref:`signature` (binary-only) with purpose 1350 // `TALER_SIGNATURE_EXCHANGE_CONFIRM_REFUND` using a current signing key of the 1351 // exchange affirming the successful refund. 1352 exchange_sig: EddsaSignature; 1353 1354 // Public EdDSA key of the exchange that was used to generate the signature. 1355 // Should match one of the exchange's signing keys from /keys. It is given 1356 // explicitly as the client might otherwise be confused by clock skew as to 1357 // which signing key was used. 1358 exchange_pub: EddsaPublicKey; 1359 1360 // Refund transaction ID. 1361 rtransaction_id: Integer; 1362 1363 // Public key of a coin that was refunded. 1364 coin_pub: EddsaPublicKey; 1365 1366 // Amount that was refunded, including refund fee charged by the exchange 1367 // to the customer. 1368 refund_amount: Amount; 1369 1370 // Timestamp when the merchant approved the refund. 1371 // Useful for grouping refunds. 1372 execution_time: Timestamp; 1373 } 1374 1375 1376 ------------------- 1377 Instance management 1378 ------------------- 1379 1380 Instances allow one merchant backend to be shared by multiple merchants. 1381 Every backend must have at least one instance, typically the "admin" 1382 instance setup before it can be used to manage inventory or process payments. 1383 1384 1385 Setting up instances 1386 ^^^^^^^^^^^^^^^^^^^^ 1387 1388 .. http:post:: /instances 1389 1390 This request will be used to create a new merchant instance in the backend. 1391 Since protocol **v21**. 1392 1393 Only available if self-provisioning is enabled. 1394 1395 **Required permission:** none 1396 1397 **Request:** 1398 1399 The request must be a `InstanceConfigurationMessage`. 1400 1401 :query token_validity_ms=DURATION: *Optional*. 1402 Pass a non-zero DURATION in milliseconds to get a 1403 refreshable login token for the SPA with the 1404 given validity duration in the response. @since **v21**. 1405 1406 **Response:** 1407 1408 :http:statuscode:`200 Ok`: 1409 The backend has successfully created the instance. Body will 1410 be an `LoginTokenSuccessResponse` with a refreshable 1411 login token for the SPA as requested. @since **v21**. 1412 :http:statuscode:`202 Accepted`: 1413 2FA is required for this operation, usually to validate the 1414 email and/or phone numbers provided for the instance. 1415 This returns the `ChallengeResponse`. @since **v21** 1416 :http:statuscode:`204 No Content`: 1417 The backend has successfully created the instance. No login 1418 token was requested, so nothing is returned. 1419 :http:statuscode:`409 Conflict`: 1420 This instance already exists, but with other configuration options. 1421 Use "PATCH" to update an instance configuration. Alternatively, 1422 the currency provided in the configuration does not match the 1423 currency supported by this backend. Another possible conflict 1424 would be if a deleted but not purged instance is known under this 1425 ID to the backend. 1426 1427 1428 .. http:post:: /instances/$INSTANCE/forgot-password 1429 1430 Same as ``/management/instances/$INSTANCE/private/auth`` it will update the password of the instance but 1431 without requiring the current password. On the first call it will validate the request 1432 and return the multi-factor authentication challenge IDs with 1433 a ``202 Accepted`` response. Once the challenges are solved the 1434 request needs to be repeated with the ``Taler-Challenge-Ids`` header. 1435 1436 This endpoint is **not** available for the ``admin`` instance. 1437 The administrator must use the command-line tool if they forgot 1438 their password. 1439 1440 Since protocol **v21** 1441 1442 **Request** the request must be an `InstanceAuthConfigurationMessage`. 1443 1444 **Response:** 1445 1446 :http:statuscode:`202 Accepted`: 1447 2FA is required for this operation. This returns 1448 the `ChallengeResponse`. @since **v21** 1449 :http:statuscode:`204 No content`: 1450 The backend has successfully changed the credentials for the instance. 1451 :http:statuscode:`404 Not found`: 1452 This instance is unknown and thus cannot be reconfigured. 1453 1454 1455 .. http:post:: /management/instances 1456 1457 This request will be used to create a new merchant instance in the backend. 1458 It is only available for the implicit ``admin`` instance. 1459 1460 **Required permission:** ``instances-write`` 1461 1462 **Request:** 1463 1464 The request must be a `InstanceConfigurationMessage`. 1465 1466 **Response:** 1467 1468 :http:statuscode:`202 Accepted`: 1469 2FA is required for this operation, usually to validate the 1470 email and/or phone numbers registered for the instance. 1471 This returns the `ChallengeResponse`. @since **v21** 1472 :http:statuscode:`204 No content`: 1473 The backend has successfully created the instance. 1474 :http:statuscode:`409 Conflict`: 1475 This instance already exists, but with other configuration options. 1476 Use "PATCH" to update an instance configuration. Alternatively, 1477 the currency provided in the configuration does not match the 1478 currency supported by this backend. Another possible conflict 1479 would be if a deleted but not purged instance is known under this 1480 ID to the backend. 1481 1482 **Details:** 1483 1484 .. ts:def:: InstanceConfigurationMessage 1485 1486 interface InstanceConfigurationMessage { 1487 1488 // Name of the merchant instance to create (will become $INSTANCE). 1489 // Must match the regex ``^[A-Za-z0-9][A-Za-z0-9_.@-]+$``. 1490 id: string; 1491 1492 // Merchant name corresponding to this instance. 1493 name: string; 1494 1495 // Merchant email for customer contact and password reset. 1496 email?: string; 1497 1498 // Merchant phone number for password reset (2-FA) 1499 // @since **v21**. 1500 phone_number?: string; 1501 1502 // Merchant public website. 1503 website?: string; 1504 1505 // Merchant logo. 1506 logo?: ImageDataUrl; 1507 1508 // Authentication settings for this instance 1509 auth: InstanceAuthConfigurationMessage; 1510 1511 // The merchant's physical address (to be put into contracts). 1512 address: Location; 1513 1514 // The jurisdiction under which the merchant conducts its business 1515 // (to be put into contracts). 1516 jurisdiction: Location; 1517 1518 // Use STEFAN curves to determine default fees? 1519 // If false, no fees are allowed by default. 1520 // Can always be overridden by the frontend on a per-order basis. 1521 use_stefan: boolean; 1522 1523 // If the frontend does NOT specify a payment deadline, how long should 1524 // offers we make be valid by default? 1525 // Optional @since **v22** (before the setting was mandatory). 1526 // If not provided, the global merchant default will be used. 1527 default_pay_delay?: RelativeTime; 1528 1529 // If the frontend does NOT specify a refund deadline, how long should 1530 // refunds be allowed by default? Added on top of the 1531 // payment deadline. 1532 // @since **v22** 1533 default_refund_delay?: RelativeTime; 1534 1535 // If the frontend does NOT specify an execution date, how long should 1536 // we tell the exchange to wait to aggregate transactions before 1537 // executing the wire transfer? This delay is added on top of 1538 // the refund deadline and afterwards subject to rounding 1539 // via the ``default_wire_transfer_rounding_interval``. 1540 // Optional @since **v22** (before the setting was mandatory). 1541 // If not provided, the global merchant default will be used. 1542 default_wire_transfer_delay?: RelativeTime; 1543 1544 // How far should the wire deadline (if computed with the help of 1545 // the ``default_wire_transfer_delay``) be rounded up to compute 1546 // the ultimate wire deadline? 1547 // @since **v22**, defaults to no rounding if not given. 1548 default_wire_transfer_rounding_interval?: RoundingInterval; 1549 } 1550 1551 .. http:post:: /management/instances/$INSTANCE/auth 1552 .. http:post:: [/instances/$INSTANCE]/private/auth 1553 1554 Update the authentication settings for an instance. POST operations against 1555 an instance are authenticated by checking that an authorization is provided 1556 that matches either the credential required by the instance being modified 1557 OR the ``admin`` instance, depending on the access path used. 1558 1559 **Required permission:** ``instances-auth-write`` 1560 1561 **Request** the request must be an `InstanceAuthConfigurationMessage`. 1562 1563 **Response:** 1564 1565 :http:statuscode:`202 Accepted`: 1566 2FA is required for this operation. This returns the `ChallengeResponse` response. @since **v21** 1567 :http:statuscode:`204 No content`: 1568 The backend has successfully changed the credentials for the instance. 1569 :http:statuscode:`404 Not found`: 1570 This instance is unknown and thus cannot be reconfigured. 1571 1572 **Details:** 1573 1574 .. ts:def:: InstanceAuthConfigurationMessage 1575 1576 type InstanceAuthConfigurationMessage = InstanceAuthConfigToken | InstanceAuthConfigTokenOLD | InstanceAuthConfigExternal 1577 1578 .. ts:def:: InstanceAuthConfigToken 1579 1580 // @since **v19** 1581 interface InstanceAuthConfigToken { 1582 // The API is accessible through API tokens. 1583 // Tokens are retrieved from the /private/token 1584 // endpoint. 1585 method: "token"; 1586 1587 // Authentication against the /private/token endpoint 1588 // is done using basic authentication with the configured password 1589 // in the "password" field. Tokens are passed to other endpoints for 1590 // authorization using RFC 8959 bearer tokens. 1591 password: string; 1592 1593 } 1594 1595 .. ts:def:: InstanceAuthConfigTokenOLD 1596 1597 // @deprecated since **v19** 1598 interface InstanceAuthConfigTokenOLD { 1599 // The API is accessible through API tokens. 1600 // Tokens are retrieved from the /private/token 1601 // endpoint. 1602 method: "token"; 1603 1604 // The value of this field MUST begin with the string "secret-token:". 1605 token: string; 1606 1607 } 1608 1609 .. ts:def:: InstanceAuthConfigExternal 1610 1611 // @deprecated since **v20** 1612 interface InstanceAuthConfigExternal { 1613 // The mechant backend does not do 1614 // any authentication checks. Instead an API 1615 // gateway must do the authentication. 1616 method: "external"; 1617 } 1618 1619 1620 .. http:post:: [/instances/$INSTANCE]/private/token 1621 1622 Retrieve an access token for the merchant API for instance 1623 ``$INSTANCE``. 1624 When accessed with a Bearer token for authentication, the token 1625 must have scope ``token-refresh`` and the requested scope must be a subset 1626 of the scope of the token. 1627 When accessed with Basic authentication the instance password must be provided 1628 along with ``$INSTANCE`` as username. 1629 1630 1631 **Required permission:** ``token-refresh`` if accessed using a Bearer token. 1632 1633 **Request:** 1634 1635 The request must be a `LoginTokenRequest`. 1636 1637 **Response:** 1638 1639 :http:statuscode:`200 Ok`: 1640 The backend is returning the access token in a 1641 `LoginTokenSuccessResponse`. 1642 :http:statuscode:`202 Accepted`: 1643 2FA is required for this operation. 1644 This returns the `ChallengeResponse`. @since **v21** 1645 1646 **Details:** 1647 1648 .. ts:def:: LoginTokenRequest 1649 1650 interface LoginTokenRequest { 1651 // Scope of the token (which kinds of operations it will allow) 1652 scope: "readonly" | "write" | "all" | "order-simple" | "order-pos" | "order-mgmt" | "order-full"; 1653 1654 // Server may impose its own upper bound 1655 // on the token validity duration 1656 duration?: RelativeTime; 1657 1658 // Optional token description 1659 description?: string; 1660 1661 // Can this token be refreshed? 1662 // Defaults to false. Deprecated since **v19**. 1663 // Use ":refreshable" scope prefix instead. 1664 refreshable?: boolean; 1665 } 1666 1667 .. ts:def:: LoginTokenSuccessResponse 1668 1669 interface LoginTokenSuccessResponse { 1670 // deprecated since v19. See access_token 1671 token: string; 1672 1673 // The login token that can be used to access resources 1674 // that are in scope for some time. Must be prefixed 1675 // with "Bearer " when used in the "Authorization" HTTP header. 1676 // Will already begin with the RFC 8959 prefix. 1677 // **Since v19** 1678 access_token: string; 1679 1680 // Scope of the token (which kinds of operations it will allow) 1681 scope: "readonly" | "write" | "all" | "order-simple" | "order-pos" | "order-mgmt" | "order-full"; 1682 1683 // Server may impose its own upper bound 1684 // on the token validity duration 1685 expiration: Timestamp; 1686 1687 // Can this token be refreshed? 1688 refreshable: boolean; 1689 } 1690 1691 .. http:get:: [/instances/$INSTANCE]/private/tokens 1692 1693 Retrieve a list of issued access tokens for ``$INSTANCE``. 1694 1695 @since **v19** 1696 1697 **Required permission**: ``tokens-read`` 1698 1699 **Request:** 1700 1701 :query limit: *Optional.* 1702 At most return the given number of results. Negative for descending by ``serial``, positive for ascending by ``serial``. Defaults to ``-20``. 1703 :query offset: *Optional.* 1704 Starting ``serial`` for :ref:`pagination <row-id-pagination>`. 1705 1706 **Response:** 1707 1708 :http:statuscode:`200 OK`: 1709 Response is a `TokenInfos`. 1710 :http:statuscode:`204 No content`: 1711 No tokens. 1712 :http:statuscode:`401 Unauthorized`: 1713 Invalid or missing credentials. 1714 :http:statuscode:`403 Forbidden`: 1715 Missing rights. 1716 1717 **Details:** 1718 1719 .. ts:def:: TokenInfos 1720 1721 interface TokenInfos { 1722 tokens: TokenInfo[]; 1723 } 1724 1725 .. ts:def:: TokenInfo 1726 1727 interface TokenInfo { 1728 // Time when the token was created. 1729 creation_time: Timestamp; 1730 1731 // Time when the token expires. 1732 expiration: Timestamp; 1733 1734 // Scope for the token. 1735 scope: "readonly" | "readwrite" | ...; 1736 1737 // Is the token refreshable into a new token during its 1738 // validity? 1739 // Refreshable tokens effectively provide indefinite 1740 // access if they are refreshed in time. 1741 refreshable: boolean; 1742 1743 // Optional token description 1744 description?: string; 1745 1746 // Opaque unique ID used for pagination. 1747 serial: Integer; 1748 } 1749 1750 .. http:delete:: [/instances/$INSTANCE]/private/tokens/$SERIAL 1751 1752 Delete a token for ``$INSTANCE`` API access by its ``$SERIAL``. 1753 1754 1755 @since **v19** 1756 1757 **Required permission**: ``tokens-write`` 1758 1759 **Response:** 1760 1761 :http:statuscode:`204 No content`: 1762 Token deleted. 1763 :http:statuscode:`401 Unauthorized`: 1764 Invalid or missing credentials. 1765 :http:statuscode:`403 Forbidden`: 1766 Missing permission. 1767 :http:statuscode:`404 Not found`: 1768 The token was not found. 1769 1770 .. http:delete:: [/instances/$INSTANCE]/private/token 1771 1772 Delete the token presented in the authorization header. 1773 1774 **Response:** 1775 1776 :http:statuscode:`204 No content`: 1777 The access token used to authorize this request was revoked. 1778 1779 .. http:patch:: /management/instances/$INSTANCE 1780 .. http:patch:: [/instances/$INSTANCE]/private 1781 1782 Update the configuration of a merchant instance. PATCH operations against 1783 an instance are authenticated by checking that an authorization is provided 1784 that matches either the credential required by the instance being modified 1785 OR the ``admin`` instance, depending on the access path used. 1786 1787 **Required permission:** ``instances-token-write`` 1788 1789 **Request** 1790 1791 The request must be a `InstanceReconfigurationMessage`. 1792 Removing an existing ``payto_uri`` deactivates 1793 the account (it will no longer be used for future contracts). 1794 1795 **Response:** 1796 1797 :http:statuscode:`204 No content`: 1798 The backend has successfully created the instance. 1799 :http:statuscode:`404 Not found`: 1800 This instance is unknown and thus cannot be reconfigured. 1801 1802 **Details:** 1803 1804 .. ts:def:: InstanceReconfigurationMessage 1805 1806 interface InstanceReconfigurationMessage { 1807 1808 // Merchant name corresponding to this instance. 1809 name: string; 1810 1811 // Merchant email for customer contact and password reset. 1812 email?: string; 1813 1814 // Merchant phone number for password reset (2-FA) 1815 // @since **v21**. 1816 phone_number?: string; 1817 1818 // Merchant public website. 1819 website?: string; 1820 1821 // Merchant logo. 1822 logo?: ImageDataUrl; 1823 1824 // The merchant's physical address (to be put into contracts). 1825 address: Location; 1826 1827 // The jurisdiction under which the merchant conducts its business 1828 // (to be put into contracts). 1829 jurisdiction: Location; 1830 1831 // Use STEFAN curves to determine default fees? 1832 // If false, no fees are allowed by default. 1833 // Can always be overridden by the frontend on a per-order basis. 1834 use_stefan: boolean; 1835 1836 // If the frontend does NOT specify a payment deadline, how long should 1837 // offers we make be valid by default? 1838 // A value of "forever" is not allowed. 1839 // Optional @since **v22** (before the setting was mandatory). 1840 // If not provided, the previous setting will now simply be preserved. 1841 default_pay_delay?: RelativeTime; 1842 1843 // If the frontend does NOT specify a refund deadline, how long should 1844 // refunds be allowed by default? Added on top of the payment deadline. 1845 // A value of "forever" is not allowed. 1846 // @since **v22** 1847 default_refund_delay?: RelativeTime; 1848 1849 // If the frontend does NOT specify an execution date, how long should 1850 // we tell the exchange to wait to aggregate transactions before 1851 // executing the wire transfer? This delay is added on top of 1852 // the refund deadline and afterwards subject to rounding 1853 // via the ``default_wire_transfer_rounding_interval``. 1854 // A value of "forever" is not allowed. 1855 // Optional @since **v22** (before the setting was mandatory). 1856 // If not provided, the previous setting will now simply be preserved. 1857 default_wire_transfer_delay?: RelativeTime; 1858 1859 // How far should the wire deadline (if computed with the help of 1860 // the ``default_wire_transfer_delay``) be rounded up to compute 1861 // the ultimate wire deadline? 1862 // @since **v22**, defaults to no rounding if not given. 1863 default_wire_transfer_rounding_interval?: RoundingInterval; 1864 } 1865 1866 1867 Inspecting instances 1868 ^^^^^^^^^^^^^^^^^^^^ 1869 1870 .. _instances: 1871 .. http:get:: /management/instances 1872 1873 This is used to return the list of all the merchant instances. 1874 It is only available for the implicit ``admin`` instance. 1875 1876 **Required permission:** ``instances-read`` 1877 1878 **Response:** 1879 1880 :http:statuscode:`200 OK`: 1881 The backend has successfully returned the list of instances stored. Returns 1882 a `InstancesResponse`. 1883 1884 **Details:** 1885 1886 .. ts:def:: InstancesResponse 1887 1888 interface InstancesResponse { 1889 // List of instances that are present in the backend (see `Instance`). 1890 instances: Instance[]; 1891 } 1892 1893 The `Instance` object describes the instance registered with the backend. 1894 It does not include the full details, only those that usually concern the frontend. 1895 It has the following structure: 1896 1897 .. ts:def:: Instance 1898 1899 interface Instance { 1900 // Merchant name corresponding to this instance. 1901 name: string; 1902 1903 // Merchant public website. 1904 website?: string; 1905 1906 // Merchant logo. 1907 logo?: ImageDataUrl; 1908 1909 // Merchant instance this response is about ($INSTANCE). 1910 id: string; 1911 1912 // Public key of the merchant/instance, in Crockford Base32 encoding. 1913 merchant_pub: EddsaPublicKey; 1914 1915 // List of the payment targets supported by this instance. Clients can 1916 // specify the desired payment target in /order requests. Note that 1917 // front-ends do not have to support wallets selecting payment targets. 1918 payment_targets: string[]; 1919 1920 // Has this instance been deleted (but not purged)? 1921 deleted: boolean; 1922 } 1923 1924 1925 .. http:get:: /management/instances/$INSTANCE 1926 .. http:get:: [/instances/$INSTANCE]/private 1927 1928 This is used to query a specific merchant instance. GET operations against 1929 an instance are authenticated by checking that an authorization is provided 1930 that matches either the credential required by the instance being modified 1931 OR the ``admin`` instance, depending on the access path used. 1932 1933 This endpoint may be used even when mandatory TAN channels 1934 were not validated yet. 1935 1936 **Required permission:** ``instances-read`` 1937 1938 **Response:** 1939 1940 :http:statuscode:`200 OK`: 1941 The backend has successfully returned the list of instances stored. Returns 1942 a `QueryInstancesResponse`. 1943 1944 **Details:** 1945 1946 .. ts:def:: QueryInstancesResponse 1947 1948 interface QueryInstancesResponse { 1949 1950 // Merchant name corresponding to this instance. 1951 name: string; 1952 1953 // Merchant email for customer contact and password reset. 1954 email?: string; 1955 1956 // True if the ``email`` address was validated. 1957 // @since **v21**. 1958 email_validated?: boolean; 1959 1960 // Merchant phone number for password reset (2-FA) 1961 // @since **v21**. 1962 phone_number?: string; 1963 1964 // True if the ``email`` address was validated. 1965 // @since **v21**. 1966 phone_validated?: boolean; 1967 1968 // Merchant public website. 1969 website?: string; 1970 1971 // Merchant logo. 1972 logo?: ImageDataUrl; 1973 1974 // Public key of the merchant/instance, in Crockford Base32 encoding. 1975 merchant_pub: EddsaPublicKey; 1976 1977 // The merchant's physical address (to be put into contracts). 1978 address: Location; 1979 1980 // The jurisdiction under which the merchant conducts its business 1981 // (to be put into contracts). 1982 jurisdiction: Location; 1983 1984 // Use STEFAN curves to determine default fees? 1985 // If false, no fees are allowed by default. 1986 // Can always be overridden by the frontend on a per-order basis. 1987 use_stefan: boolean; 1988 1989 // If the frontend does NOT specify a payment deadline, how long should 1990 // offers we make be valid by default? Added to the order creation 1991 // time. 1992 default_pay_delay: RelativeTime; 1993 1994 // If the frontend does NOT specify a refund deadline, how long should 1995 // refunds be allowed by default? Added to the payment deadline. 1996 // @since **v22** 1997 default_refund_delay: RelativeTime; 1998 1999 // If the frontend does NOT specify an execution date, how long should 2000 // we tell the exchange to wait to aggregate transactions before 2001 // executing the wire transfer? This delay is added to the 2002 // refund deadline and subject to rounding to the 2003 // ``default_wire_transfer_rounding_interval``. 2004 default_wire_transfer_delay: RelativeTime; 2005 2006 // Default interval to which wire deadlines computed by 2007 // adding the wire_transfer_delay on top of the refund 2008 // deadline should be rounded up to. 2009 // @since **v23** 2010 default_wire_transfer_rounding_interval: RoundingInterval; 2011 2012 // Authentication configuration. 2013 // Does not contain the token when token auth is configured. 2014 auth: { 2015 method: "external" | "token"; 2016 }; 2017 2018 } 2019 2020 2021 Getting statistics 2022 ^^^^^^^^^^^^^^^^^^ 2023 2024 .. http:get:: /management/instances/$INSTANCE/statistics-amount/$SLUG 2025 .. http:get:: [/instances/$INSTANCE]/private/statistics-amount/$SLUG 2026 2027 This request will return be used to statistics where the 2028 values are amounts. All available values for the given 2029 SLUG will be returned. 2030 Since protocol **vSTATISTICS**. 2031 2032 **Required permission:** ``statistics-read`` 2033 2034 **Request:** 2035 2036 :query by: *Optional*. If set to "BUCKET", only statistics by bucket will be returned. If set to "INTERVAL", only statistics kept by interval will be returned. If not set or set to "ANY", both will be returned. 2037 2038 **Response:** 2039 2040 :http:statuscode:`200 Ok`: 2041 The body will be a `MerchantStatisticsAmountResponse` 2042 :http:statuscode:`401 Unauthorized`: 2043 The request is unauthorized. 2044 :http:statuscode:`404 Not found`: 2045 The instance is unknown to the backend. 2046 2047 **Details:** 2048 2049 .. ts:def:: MerchantStatisticsAmountResponse 2050 2051 interface MerchantStatisticsAmountResponse { 2052 2053 // Statistics kept for a particular fixed time window. 2054 buckets: MerchantStatisticAmountByBucket[]; 2055 2056 // Human-readable bucket statistic description. 2057 // Unset if no buckets returned 2058 buckets_description?: string; 2059 2060 // Statistics kept for a particular sliding interval. 2061 intervals: MerchantStatisticAmountByInterval[]; 2062 2063 // Human-readable interval statistic description. 2064 // Unset if no buckets returned 2065 intervals_description?: string; 2066 } 2067 2068 .. ts:def:: MerchantStatisticAmountByBucket 2069 2070 interface MerchantStatisticAmountByBucket { 2071 2072 // Start time of the bucket (inclusive) 2073 start_time: Timestamp; 2074 2075 // End time of the bucket (exclusive) 2076 end_time: Timestamp; 2077 2078 // Range of the bucket 2079 range: StatisticBucketRange; 2080 2081 // Sum of all amounts falling under the given 2082 // SLUG within this timeframe. 2083 cumulative_amounts: Amount[]; 2084 2085 } 2086 2087 .. ts:def:: MerchantStatisticAmountByInterval 2088 2089 interface MerchantStatisticAmountByInterval { 2090 2091 // Start time of the interval. 2092 // The interval always ends at the response 2093 // generation time. 2094 start_time: Timestamp; 2095 2096 // Sum of all amounts falling under the given 2097 // SLUG within this timeframe. 2098 cumulative_amounts: Amount[]; 2099 2100 } 2101 2102 .. http:get:: /management/instances/$INSTANCE/statistics-counter/$SLUG 2103 .. http:get:: [/instances/$INSTANCE]/private/statistics-counter/$SLUG 2104 2105 This request will return be used to statistics where the 2106 values are counters. All available values for the given 2107 SLUG will be returned. 2108 Since protocol **vSTATISTICS**. 2109 2110 **Required permission:** ``statistics-read`` 2111 2112 **Request:** 2113 2114 :query by: *Optional*. If set to "BUCKET", only statistics by bucket will be returned. If set to "INTERVAL", only statistics kept by interval will be returned. If not set or set to "ANY", both will be returned. 2115 2116 **Response:** 2117 2118 :http:statuscode:`200 Ok`: 2119 The body will be a `MerchantStatisticsCounterResponse` 2120 :http:statuscode:`401 Unauthorized`: 2121 The request is unauthorized. 2122 :http:statuscode:`404 Not found`: 2123 The instance is unknown to the backend. 2124 2125 **Details:** 2126 2127 .. ts:def:: MerchantStatisticsCounterResponse 2128 2129 interface MerchantStatisticsCounterResponse { 2130 2131 // Statistics kept for a particular fixed time window. 2132 buckets: MerchantStatisticCounterByBucket[]; 2133 2134 // Human-readable bucket statistic description. 2135 // Unset if no buckets returned 2136 buckets_description?: string; 2137 2138 // Statistics kept for a particular sliding interval. 2139 intervals: MerchantStatisticCounterByInterval[]; 2140 2141 // Human-readable interval statistic description. 2142 // Unset if no intervals returned 2143 intervals_description?: string; 2144 2145 } 2146 2147 .. ts:def:: MerchantStatisticCounterByBucket 2148 2149 interface MerchantStatisticCounterByBucket { 2150 2151 // Start time of the bucket (inclusive) 2152 start_time: Timestamp; 2153 2154 // End time of the bucket (exclusive) 2155 end_time: Timestamp; 2156 2157 // Range of the bucket 2158 range: StatisticBucketRange; 2159 2160 // Sum of all counters falling under the given 2161 // SLUG within this timeframe. 2162 cumulative_counter: Integer; 2163 2164 } 2165 2166 .. ts:def:: MerchantStatisticCounterByInterval 2167 2168 interface MerchantStatisticCounterByInterval { 2169 2170 // Start time of the interval. 2171 // The interval always ends at the response 2172 // generation time. 2173 start_time: Timestamp; 2174 2175 // Sum of all counters falling under the given 2176 // SLUG within this timeframe. 2177 cumulative_counter: Integer; 2178 2179 } 2180 2181 Deleting instances 2182 ^^^^^^^^^^^^^^^^^^ 2183 2184 .. http:delete:: /management/instances/$INSTANCE 2185 .. http:delete:: [/instances/$INSTANCE]/private 2186 2187 This request will be used to delete (permanently disable) 2188 or purge merchant instance in the backend. Purging will 2189 delete all offers and payments associated with the instance, 2190 while disabling (the default behavior) only deletes the private key 2191 and makes the instance unusable for new orders or payments. 2192 2193 For deletion, the authentication credentials must match 2194 the instance that is being deleted or the ``admin`` 2195 instance, depending on the access path used. 2196 2197 **Required permission:** ``instances-write`` 2198 2199 **Request:** 2200 2201 :query purge: *Optional*. If set to YES, the instance will be fully 2202 deleted. Otherwise only the private key would be deleted. 2203 2204 **Response:** 2205 2206 :http:statuscode:`202 Accepted`: 2207 2FA is required for this operation, usually to validate the 2208 email and/or phone numbers registered for the instance. 2209 This returns the `ChallengeResponse`. @since **v21** 2210 :http:statuscode:`204 No content`: 2211 The backend has successfully removed the instance. The body is empty. 2212 :http:statuscode:`401 Unauthorized`: 2213 The request is unauthorized. Note that for already deleted instances, 2214 the request must be authorized using the ``admin`` instance. 2215 :http:statuscode:`404 Not found`: 2216 The instance is unknown to the backend. 2217 :http:statuscode:`409 Conflict`: 2218 The instance cannot be deleted because it has pending offers, or 2219 the instance cannot be purged because it has successfully processed 2220 payments that have not passed the ``TAX_RECORD_EXPIRATION`` time. 2221 The latter case only applies if ``purge`` was set. 2222 2223 2224 KYC status checks 2225 ^^^^^^^^^^^^^^^^^ 2226 2227 .. _merchantkycstatus: 2228 2229 .. http:GET:: /management/instances/$INSTANCE/kyc 2230 .. http:GET:: /instances/$INSTANCE/private/kyc 2231 2232 Check KYC status of a particular payment target. 2233 Prompts the exchange to inquire with the bank 2234 as to the KYC status of the respective account 2235 and returns the result. 2236 2237 **Required permission:** ``instances-kyc-read`` 2238 2239 **Request:** 2240 2241 :query h_wire=H_WIRE: *Optional*. If specified, the KYC check should return the KYC status only for this wire account. Otherwise, for all wire accounts. 2242 :query exchange_url=URL: *Optional*. If specified, the KYC check should return the KYC status only for the given exchange. Otherwise, for all exchanges we interacted with. 2243 :query lpt=TARGET: *Optional*. 2244 Specifies what status change we are long-polling for. 2245 Use 1 to wait for the KYC auth transfer (access token available), 2246 2 to wait for an AML investigation to be done, 2247 and 3 to wait for the KYC status to be OK. 2248 If multiple accounts or exchanges match the query, 2249 any account reaching the TARGET state will cause 2250 the response to be returned. 2251 Since protocol **v17**. 2252 :query timeout_ms=NUMBER: *Optional.* If specified, the merchant will 2253 wait up to ``timeout_ms`` milliseconds for the exchanges to confirm completion of the KYC process(es). 2254 2255 **Response:** 2256 2257 If different exchanges cause different errors when processing 2258 the request, the largest HTTP status code that is applicable 2259 is returned. 2260 2261 :http:statuscode:`200 Ok`: 2262 The user may be redirected to the provided locations to perform 2263 KYC checks. 2264 The response will be a `MerchantAccountKycRedirectsResponse` object. 2265 Uses this status code and format only since protocol **v17**. 2266 :http:statuscode:`204 No content`: 2267 No possibilities for KYC operations exist. 2268 This may change in the future, but there is 2269 no need to check again soon. This will most likely 2270 change if accounts are added to the instance. 2271 2272 **Details:** 2273 2274 .. ts:def:: MerchantAccountKycRedirectsResponse 2275 2276 interface MerchantAccountKycRedirectsResponse { 2277 2278 // Array of KYC status information for 2279 // the exchanges and bank accounts selected 2280 // by the query. 2281 kyc_data: MerchantAccountKycRedirect[]; 2282 2283 } 2284 2285 .. ts:def:: MerchantAccountKycRedirect 2286 2287 interface MerchantAccountKycRedirect { 2288 2289 // Summary of the status of the KYC process. Possible values are: 2290 // 2291 // o "no-exchange-keys": we do not (yet) have the /keys of the exchange 2292 // - "kyc-wire-impossible": KYC auth transfer needed but not possible 2293 // @ "kyc-wire-required": KYC auth transfer still needed and possible 2294 // @ "kyc-required": merchant must supply KYC data to proceed (incl. 2295 // in case of exposed zero-limits on deposit/aggregation) 2296 // + "awaiting-aml-review": account under review by payment provider 2297 // + "ready": everything is fine, account can be fully used 2298 // - "logic-bug": merchant backend logic bug 2299 // o "merchant-internal-error": merchant had an internal error 2300 // o "exchange-internal-error": exchange had an internal error 2301 // o "exchange-gateway-timeout": network timeout at gateway 2302 // o "exchange-unreachable": exchange did not respond at all 2303 // - "exchange-status-invalid": exchange violated protocol in reply 2304 // 2305 // "+" are perfectly normal states, "@" are states where the user 2306 // must performn an action (show link!); "o" are reasonable transient 2307 // states that could happen and are we are expected to likely recover 2308 // from automatically but that we should inform the user about 2309 // (show in yellow?), "-" are hard error states from which 2310 // there is likely no good automatic recovery from (show in red?). 2311 status: string; 2312 2313 // Full payto URI of the bank wire account this is about. 2314 payto_uri: string; 2315 2316 // Hash of the salted payto://-URI of our 2317 // bank wire account this is about. 2318 // Since protocol **v17**. 2319 h_wire: string; 2320 2321 // Base URL of the exchange this is about. 2322 exchange_url: string; 2323 2324 // HTTP status code returned by the exchange when we asked for 2325 // information about the KYC status. 2326 // Since protocol **v17**. 2327 exchange_http_status: Integer; 2328 2329 // True if we did not get a ``/keys`` response from 2330 // the exchange and thus cannot do certain checks, such as 2331 // determining default account limits or account eligibility. 2332 no_keys: boolean; 2333 2334 // True if the given account cannot to KYC at the 2335 // given exchange because no wire method exists that could 2336 // be used to do the KYC auth wire transfer. 2337 auth_conflict: boolean; 2338 2339 // Numeric `error code <error-codes>` indicating errors the exchange 2340 // returned, or TALER_EC_INVALID for none. 2341 // Optional (as there may not always have 2342 // been an error code). Since protocol **v17**. 2343 exchange_code?: Integer; 2344 2345 // Access token needed to open the KYC SPA and/or 2346 // access the ``/kyc-info/`` endpoint. 2347 access_token?: AccountAccessToken; 2348 2349 // Array with limitations that currently apply to this 2350 // account and that may be increased or lifted if the 2351 // KYC check is passed. 2352 // Note that additional limits *may* exist and not be 2353 // communicated to the client. If such limits are 2354 // reached, this *may* be indicated by the account 2355 // going into ``aml_review`` state. However, it is 2356 // also possible that the exchange may legally have 2357 // to deny operations without being allowed to provide 2358 // any justification. 2359 // The limits should be used by the client to 2360 // possibly structure their operations (e.g. withdraw 2361 // what is possible below the limit, ask the user to 2362 // pass KYC checks or withdraw the rest after the time 2363 // limit is passed, warn the user to not withdraw too 2364 // much or even prevent the user from generating a 2365 // request that would cause it to exceed hard limits). 2366 limits?: AccountLimit[]; 2367 2368 // Array of full payto://-URIs with 2369 // wire transfer instructions (including 2370 // optional amount and subject) for a KYC auth wire 2371 // transfer. Set only if this is required 2372 // to get the given exchange working. 2373 // Array because the exchange may have multiple 2374 // bank accounts, in which case any of these 2375 // accounts will do. 2376 // Optional. Since protocol **v17**. 2377 payto_kycauths?: string[]; 2378 2379 } 2380 2381 2382 ------------- 2383 Bank Accounts 2384 ------------- 2385 2386 One or more bank accounts must be associated with an instance 2387 so that the instance can receive payments. Payments may be made 2388 into any of the active bank accounts of an instance. 2389 2390 2391 .. http:post:: [/instances/$INSTANCE]/private/accounts 2392 2393 This is used to add an account to an instance. 2394 2395 **Required permission:** ``accounts-write`` 2396 2397 **Request:** 2398 2399 The request must have an `AccountAddDetails` body. 2400 2401 **Response:** 2402 2403 :http:statuscode:`200 Ok`: 2404 Adding the account was successful, we return the salt selected by the backend and the resulting wire hash in an `AccountAddResponse`. 2405 :http:statuscode:`202 Accepted`: 2406 2FA is required for this operation, usually to validate the 2407 email and/or phone numbers registered for the instance. 2408 This returns the `ChallengeResponse`. @since **v21** 2409 :http:statuscode:`404 Not found`: 2410 The merchant instance is unknown or it is not in our data. 2411 :http:statuscode:`409 Conflict`: 2412 The provided information is inconsistent with the current state of the instance. 2413 Usually this means we already have this account, but with conflicting credit facade information. 2414 Inactive accounts can be reactivated using this method even if the 2415 credit facade information differs from the previous state. 2416 2417 **Details:** 2418 2419 .. ts:def:: AccountAddDetails 2420 2421 interface AccountAddDetails { 2422 2423 // Full payto:// URI of the account. 2424 payto_uri: string; 2425 2426 // URL from where the merchant can download information 2427 // about incoming wire transfers to this account. 2428 credit_facade_url?: string; 2429 2430 // Credentials to use when accessing the credit facade. 2431 // Never returned on a GET (as this may be somewhat 2432 // sensitive data). Can be set in POST 2433 // or PATCH requests to update (or delete) credentials. 2434 // To really delete credentials, set them to the type: "none". 2435 credit_facade_credentials?: FacadeCredentials; 2436 2437 } 2438 2439 .. ts:def:: FacadeCredentials 2440 2441 type FacadeCredentials = 2442 | NoFacadeCredentials 2443 | BasicAuthFacadeCredentials; 2444 2445 .. ts:def:: NoFacadeCredentials 2446 2447 interface NoFacadeCredentials { 2448 type: "none"; 2449 }; 2450 2451 .. ts:def:: BasicAuthFacadeCredentials 2452 2453 interface BasicAuthFacadeCredentials { 2454 type: "basic"; 2455 2456 // Username to use to authenticate 2457 username: string; 2458 2459 // Password to use to authenticate 2460 password: string; 2461 }; 2462 2463 .. ts:def:: AccountAddResponse 2464 2465 interface AccountAddResponse { 2466 2467 // Hash over the wire details (including over the salt). 2468 h_wire: HashCode; 2469 2470 // Salt used to compute h_wire. 2471 salt: HashCode; 2472 2473 } 2474 2475 2476 .. http:patch:: [/instances/$INSTANCE]/private/accounts/$H_WIRE 2477 2478 This is used to update a bank account. 2479 2480 **Required permission:** ``accounts-write`` 2481 2482 **Request:** 2483 2484 The request must be a `AccountPatchDetails`. 2485 2486 **Response:** 2487 2488 :http:statuscode:`204 No content`: 2489 The account has successfully modified. 2490 :http:statuscode:`404 Not found`: 2491 The account (``H_WIRE``) is unknown to the backend. 2492 2493 **Details:** 2494 2495 .. ts:def:: AccountPatchDetails 2496 2497 interface AccountPatchDetails { 2498 2499 // URL from where the merchant can download information 2500 // about incoming wire transfers to this account. 2501 credit_facade_url?: string; 2502 2503 // Credentials to use when accessing the credit facade. 2504 // Never returned on a GET (as this may be somewhat 2505 // sensitive data). Can be set in POST 2506 // or PATCH requests to update (or delete) credentials. 2507 // To really delete credentials, set them to the type: "none". 2508 // If the argument is omitted, the old credentials 2509 // are simply preserved. 2510 credit_facade_credentials?: FacadeCredentials; 2511 } 2512 2513 2514 .. http:get:: [/instances/$INSTANCE]/private/accounts 2515 2516 This is used to return the list of all the bank accounts 2517 of an instance. 2518 2519 **Required permission:** ``accounts-read`` 2520 2521 **Response:** 2522 2523 :http:statuscode:`200 OK`: 2524 The backend has successfully returned all the accounts. Returns a `AccountsSummaryResponse`. 2525 :http:statuscode:`404 Not found`: 2526 The backend has does not know about the instance. 2527 2528 **Details:** 2529 2530 .. ts:def:: AccountsSummaryResponse 2531 2532 interface AccountsSummaryResponse { 2533 2534 // List of accounts that are known for the instance. 2535 accounts: BankAccountEntry[]; 2536 } 2537 2538 .. ts:def:: BankAccountEntry 2539 2540 interface BankAccountEntry { 2541 2542 // Full payto:// URI of the account. 2543 payto_uri: string; 2544 2545 // Hash over the wire details (including over the salt). 2546 h_wire: HashCode; 2547 2548 // true if this account is active, 2549 // false if it is historic. 2550 active: boolean; 2551 } 2552 2553 .. http:get:: [/instances/$INSTANCE]/private/accounts/$H_WIRE 2554 2555 This is used to obtain detailed information about a specific bank account. 2556 2557 2558 **Required permission:** ``accounts-read`` 2559 2560 **Response:** 2561 2562 :http:statuscode:`200 OK`: 2563 The backend has successfully returned the detailed information about a specific bank account. 2564 Returns a `BankAccountDetail`. 2565 :http:statuscode:`404 Not found`: 2566 The bank account or instance is unknown to the backend. 2567 2568 **Details:** 2569 2570 .. ts:def:: BankAccountDetail 2571 2572 interface BankAccountDetail { 2573 2574 // Full payto:// URI of the account. 2575 payto_uri: string; 2576 2577 // Hash over the wire details (including over the salt). 2578 h_wire: HashCode; 2579 2580 // Salt used to compute h_wire. 2581 salt: HashCode; 2582 2583 // URL from where the merchant can download information 2584 // about incoming wire transfers to this account. 2585 credit_facade_url?: string; 2586 2587 // true if this account is active, 2588 // false if it is historic. 2589 active: boolean; 2590 } 2591 2592 2593 2594 .. http:delete:: [/instances/$INSTANCE]/private/accounts/$H_WIRE 2595 2596 **Required permission:** ``accounts-write`` 2597 2598 **Response:** 2599 2600 :http:statuscode:`204 No content`: 2601 The backend has successfully deactivated the account. 2602 :http:statuscode:`404 Not found`: 2603 The backend does not know the instance or the account. 2604 2605 2606 -------------------- 2607 Inventory management 2608 -------------------- 2609 2610 .. _inventory: 2611 2612 Inventory management is an *optional* backend feature that can be used to 2613 manage limited stocks of products and to auto-complete product descriptions in 2614 contracts (such that the frontends have to do less work). You can use the 2615 Taler merchant backend to process payments *without* using its inventory 2616 management. 2617 2618 2619 Managing measurement units 2620 ^^^^^^^^^^^^^^^^^^^^^^^^^^ 2621 2622 .. http:get:: [/instances/$INSTANCE]/private/units 2623 2624 Returns the list of measurement units available to an instance. 2625 2626 **Required permission:** ``units-read`` 2627 2628 **Response:** 2629 2630 :http:statuscode:`200 OK`: 2631 The backend returned the unit catalog. The body is a `UnitListResponse`. 2632 2633 **Details:** 2634 2635 .. ts:def:: UnitListResponse 2636 2637 interface UnitListResponse { 2638 units: MerchantUnit[]; 2639 } 2640 2641 .. ts:def:: MerchantUnit 2642 2643 interface MerchantUnit { 2644 // Unique serial for the unit. 2645 unit_serial: Integer; 2646 2647 // Short identifier used in product definitions. 2648 unit: string; 2649 2650 // Human-readable long label. 2651 unit_name_long: string; 2652 2653 // Human-readable short label. 2654 unit_name_short: string; 2655 2656 // Optional translations for the long label. 2657 unit_name_long_i18n?: { [lang_tag: string]: string }; 2658 2659 // Optional translations for the short label. 2660 unit_name_short_i18n?: { [lang_tag: string]: string }; 2661 2662 // Whether fractional quantities are allowed for this unit. 2663 unit_allow_fraction: boolean; 2664 2665 // Maximum fractional precision (0-6) enforced for this unit. 2666 unit_precision_level: Integer; 2667 2668 // Whether the unit is currently active. 2669 unit_active: boolean; 2670 2671 // True if the unit is provided by the backend and cannot be removed. 2672 unit_builtin: boolean; 2673 } 2674 2675 .. http:get:: [/instances/$INSTANCE]/private/units/$UNIT 2676 2677 Fetch details for a single measurement unit. 2678 2679 **Required permission:** ``units-read`` 2680 2681 **Response:** 2682 2683 :http:statuscode:`200 OK`: 2684 The backend returned the unit definition. The body is a `MerchantUnit`. 2685 :http:statuscode:`404 Not found`: 2686 The unit is unknown to the backend. 2687 2688 .. http:post:: [/instances/$INSTANCE]/private/units 2689 2690 Create a custom measurement unit or reactivate a previously disabled one. 2691 2692 **Required permission:** ``units-write`` 2693 2694 **Request:** 2695 2696 The request must be a `UnitAddRequest`. 2697 2698 **Response:** 2699 2700 :http:statuscode:`204 No content`: 2701 The backend added the unit. 2702 :http:statuscode:`409 Conflict`: 2703 A built-in unit with the same short name already exists. 2704 2705 .. ts:def:: UnitAddRequest 2706 2707 interface UnitAddRequest { 2708 // Short identifier to reference the unit from products and orders. 2709 unit: string; 2710 2711 // Human-readable long label (e.g. "kilogram"). 2712 unit_name_long: string; 2713 2714 // Human-readable short label (e.g. "kg"). 2715 unit_name_short: string; 2716 2717 // Optional translations for the long label keyed by BCP 47 language tags. 2718 unit_name_long_i18n?: { [lang_tag: string]: string }; 2719 2720 // Optional translations for the short label keyed by BCP 47 language tags. 2721 unit_name_short_i18n?: { [lang_tag: string]: string }; 2722 2723 // Defaults to false; set to true to enable fractional quantities. 2724 unit_allow_fraction?: boolean; 2725 2726 // Fractional precision (0-6). Ignored when ``unit_allow_fraction`` is false. 2727 unit_precision_level?: Integer; 2728 2729 // Defaults to true. 2730 unit_active?: boolean; 2731 } 2732 2733 .. http:patch:: [/instances/$INSTANCE]/private/units/$UNIT 2734 2735 Update attributes of a measurement unit. 2736 2737 **Required permission:** ``units-write`` 2738 2739 **Request:** 2740 2741 The request must be a `UnitPatchRequest`. 2742 2743 **Response:** 2744 2745 :http:statuscode:`204 No content`: 2746 The backend updated the unit. 2747 :http:statuscode:`404 Not found`: 2748 The unit is unknown to the backend. 2749 2750 Built-in units allow changing ``unit_allow_fraction``, ``unit_precision_level``, and 2751 ``unit_active``; other fields are immutable for built-ins. 2752 2753 .. ts:def:: UnitPatchRequest 2754 2755 interface UnitPatchRequest { 2756 // Updated human-readable long label. 2757 unit_name_long?: string; 2758 2759 // Updated human-readable short label. 2760 unit_name_short?: string; 2761 2762 // Updated translations for the long label keyed by BCP 47 language tags. 2763 unit_name_long_i18n?: { [lang_tag: string]: string }; 2764 2765 // Updated translations for the short label keyed by BCP 47 language tags. 2766 unit_name_short_i18n?: { [lang_tag: string]: string }; 2767 2768 // Override to allow or forbid fractional quantities. 2769 unit_allow_fraction?: boolean; 2770 2771 // Override for the fractional precision (0-6). Ignored if fractions are disabled. 2772 unit_precision_level?: Integer; 2773 2774 // Toggle whether the unit is active. 2775 unit_active?: boolean; 2776 } 2777 2778 Fractional precision is capped at six decimal places. Disabling 2779 ``unit_allow_fraction`` forces ``unit_precision_level`` to zero. 2780 2781 .. http:delete:: [/instances/$INSTANCE]/private/units/$UNIT 2782 2783 Remove a custom unit from an instance. 2784 2785 **Required permission:** ``units-write`` 2786 2787 **Response:** 2788 2789 :http:statuscode:`204 No content`: 2790 The unit was removed. 2791 :http:statuscode:`404 Not found`: 2792 The unit is unknown to the backend. 2793 :http:statuscode:`409 Conflict`: 2794 Built-in units cannot be deleted. 2795 2796 2797 Managing product categories 2798 ^^^^^^^^^^^^^^^^^^^^^^^^^^^ 2799 2800 .. http:get:: [/instances/$INSTANCE]/private/categories 2801 2802 This request returns the known product categories 2803 and the number of products in each category. 2804 Since API version **v16**. 2805 2806 **Required permission:** ``categories-read`` 2807 2808 **Response:** 2809 2810 :http:statuscode:`200 Ok`: 2811 The body is a `CategoryListResponse`. 2812 2813 **Details:** 2814 2815 .. ts:def:: CategoryListResponse 2816 2817 interface CategoryListResponse { 2818 2819 // Array with all of the categories we know. 2820 categories: CategoryListEntry[]; 2821 2822 } 2823 2824 .. ts:def:: CategoryListEntry 2825 2826 interface CategoryListEntry { 2827 2828 // Unique number for the category. 2829 category_id: Integer; 2830 2831 // Name of the category. 2832 name: string; 2833 2834 // Translations of the name into various 2835 // languages. 2836 name_i18n?: { [lang_tag: string]: string }; 2837 2838 // Number of products in this category. 2839 // A product can be in more than one category. 2840 product_count: Integer; 2841 2842 } 2843 2844 .. http:get:: [/instances/$INSTANCE]/private/categories/$CATEGORY_ID 2845 2846 This request returns the known products in the given 2847 category. 2848 Since API version **v16**. 2849 2850 **Required permission:** ``categories-read`` 2851 2852 **Response:** 2853 2854 :http:statuscode:`200 Ok`: 2855 The body is a `CategoryProductList`. 2856 2857 **Details:** 2858 2859 .. ts:def:: CategoryProductList 2860 2861 interface CategoryProductList { 2862 2863 // Name of the category. 2864 name: string; 2865 2866 // Translations of the name into various 2867 // languages. 2868 name_i18n?: { [lang_tag: string]: string }; 2869 2870 // The products in this category. 2871 products: CategoryProductSummary[]; 2872 2873 } 2874 2875 .. ts:def:: CategoryProductSummary 2876 2877 interface CategoryProductSummary { 2878 2879 // ID of a product in the category. 2880 product_id: string; 2881 2882 } 2883 2884 2885 .. http:post:: [/instances/$INSTANCE]/private/categories 2886 2887 This is used to create a new category for the inventory. 2888 Since API version **v16**. 2889 2890 **Required permission:** ``categories-write`` 2891 2892 **Request:** 2893 2894 The request is a `CategoryCreateRequest`. 2895 2896 **Response:** 2897 2898 :http:statuscode:`200 Ok`: 2899 The response is a `CategoryCreatedResponse`. 2900 2901 **Details:** 2902 2903 .. ts:def:: CategoryCreateRequest 2904 2905 interface CategoryCreateRequest { 2906 2907 // Name of the category. 2908 name: string; 2909 2910 // Translations of the name into various 2911 // languages. 2912 name_i18n?: { [lang_tag: string]: string }; 2913 2914 } 2915 2916 .. ts:def:: CategoryCreatedResponse 2917 2918 interface CategoryCreatedResponse { 2919 2920 // Number of the newly created category. 2921 category_id: Integer; 2922 } 2923 2924 2925 .. http:patch:: [/instances/$INSTANCE]/private/categories/$CATEGORY_ID 2926 2927 This is used to edit a category. 2928 Since API version **v16**. 2929 2930 **Required permission:** ``categories-write`` 2931 2932 **Request:** 2933 2934 The request is a `CategoryCreateRequest`. 2935 2936 **Response:** 2937 2938 :http:statuscode:`204 No Content`: 2939 The category was modified successfully. 2940 2941 .. http:delete:: [/instances/$INSTANCE]/private/categories/$CATEGORY_ID 2942 2943 This is used to delete a category. 2944 Since API version **v16**. 2945 2946 **Required permission:** ``categories-write`` 2947 2948 **Response:** 2949 2950 :http:statuscode:`204 No Content`: 2951 The category was deleted. 2952 :http:statuscode:`404 Not Found`: 2953 The category was possibly already deleted or is unknown. 2954 2955 2956 Adding products to the inventory 2957 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 2958 2959 2960 .. http:post:: [/instances/$INSTANCE]/private/products 2961 2962 This is used to add a product to the inventory. 2963 2964 **Required permission:** ``products-write`` 2965 2966 **Request:** 2967 2968 The request must be a `ProductAddDetail`. 2969 2970 **Response:** 2971 2972 :http:statuscode:`204 No content`: 2973 The backend has successfully expanded the inventory. 2974 :http:statuscode:`409 Conflict`: 2975 The backend already knows a product with this product ID, but with different details. 2976 2977 **Details:** 2978 2979 .. ts:def:: ProductAddDetail 2980 2981 interface ProductAddDetail { 2982 2983 // Product ID to use. 2984 product_id: string; 2985 2986 // Human-readable product name. 2987 // Since API version **v20**. Optional only for 2988 // backwards-compatibility, should be considered mandatory 2989 // moving forward! 2990 product_name?: string; 2991 2992 // Human-readable product description. 2993 description: string; 2994 2995 // Map from IETF BCP 47 language tags to localized descriptions. 2996 description_i18n?: { [lang_tag: string]: string }; 2997 2998 // Categories into which the product belongs. 2999 // Used in the POS-endpoint. 3000 // Since API version **v16**. 3001 categories?: Integer[]; 3002 3003 // Unit in which the product is measured (liters, kilograms, packages, etc.). 3004 unit: string; 3005 3006 // Optional override to control whether fractional quantities are permitted. 3007 // Defaults to the policy implied by ``unit``. 3008 unit_allow_fraction?: boolean; 3009 3010 // Override for the fractional precision level (0-6). Only relevant if 3011 // ``unit_allow_fraction`` is true. Defaults come from ``unit``. 3012 unit_precision_level?: Integer; 3013 3014 // Preferred way to express inventory counts using "<integer>[.<fraction>]" syntax. 3015 // Use "-1" for unlimited stock. Required unless ``total_stock`` is provided. 3016 unit_total_stock?: string; 3017 3018 // Legacy stock counter. Deprecated, use ``unit_total_stock`` instead. 3019 // Still required when ``unit_total_stock`` is omitted. 3020 total_stock?: Integer; 3021 3022 // Preferred way to express the per-unit price of the product. Supply at least one entry; 3023 // the first entry represents the base price and MUST include applicable taxes. 3024 // Zero implies that the product is not sold separately or that the price must be supplied 3025 // by the frontend. 3026 unit_price?: Amount[]; 3027 3028 // Legacy price field. Deprecated; when present it must match the first element of ``unit_price``. 3029 price?: Amount; 3030 3031 // An optional base64-encoded product image. 3032 image?: ImageDataUrl; 3033 3034 // A list of taxes paid by the merchant for one unit of this product. 3035 taxes?: Tax[]; 3036 3037 // Identifies where the product is in stock. 3038 address?: Location; 3039 3040 // Identifies when we expect the next restocking to happen. 3041 next_restock?: Timestamp; 3042 3043 // Minimum age buyer must have (in years). Default is 0. 3044 minimum_age?: Integer; 3045 3046 } 3047 3048 Clients SHOULD migrate to the new ``unit_*`` fields and treat ``total_stock`` and ``price`` 3049 as deprecated compatibility shims. If both the legacy and the new representation are supplied, 3050 their values must match. Omitting both ``unit_total_stock`` and ``total_stock`` (or both 3051 ``unit_price`` and ``price``) results in a ``400 Bad Request``. When only ``price`` is given, 3052 the backend treats it as a one-element ``unit_price`` array. 3053 3054 ``unit_total_stock`` uses a fixed-point decimal string in the form ``INTEGER[.FRACTION]`` with 3055 at most six fractional digits. Scientific notation or special values such as ``NaN`` are not 3056 accepted. Supply ``"-1"`` to represent unlimited stock. 3057 3058 Fractional behaviour defaults to the value of ``unit``. The backend disables fractions for 3059 ``Piece``, ``Set``, ``Custom``, ``WeightUnitMg`` and ``SizeUnitMm``. Other predefined units 3060 allow fractional quantities with the following default precision levels: 3061 3062 - Precision ``1``: ``WeightUnitG``, ``SizeUnitCm``, ``SurfaceUnitMm2``, ``VolumeUnitMm3``. 3063 - Precision ``2``: ``WeightUnitOunce``, ``SizeUnitInch``, ``SurfaceUnitCm2``, 3064 ``VolumeUnitInch3``, ``VolumeUnitOunce``, ``TimeUnitHour``, ``TimeUnitMonth``. 3065 - Precision ``3``: ``WeightUnitTon``, ``WeightUnitKg``, ``WeightUnitPound``, ``SizeUnitM``, 3066 ``SizeUnitDm``, ``SizeUnitFoot``, ``SurfaceUnitDm2``, ``SurfaceUnitFoot2``, ``VolumeUnitCm3``, 3067 ``VolumeUnitLitre``, ``VolumeUnitGallon``, ``TimeUnitSecond``, ``TimeUnitMinute``, 3068 ``TimeUnitDay``, ``TimeUnitWeek``. 3069 - Precision ``4``: ``SurfaceUnitM2``, ``SurfaceUnitInch2``, ``TimeUnitYear``. 3070 - Precision ``5``: ``VolumeUnitDm3``, ``VolumeUnitFoot3``. 3071 - Precision ``6``: ``VolumeUnitM3``. 3072 3073 Integrations can override these defaults by explicitly setting ``unit_allow_fraction`` and/or 3074 ``unit_precision_level``. 3075 3076 3077 .. http:patch:: [/instances/$INSTANCE]/private/products/$PRODUCT_ID 3078 3079 This is used to update product details in the inventory. Note that the 3080 ``total_stock`` and ``total_lost`` numbers MUST be greater or equal than 3081 previous values (this design ensures idempotency). In case stocks were lost 3082 but not sold, increment the ``total_lost`` number. All fields in the 3083 request are optional, those that are not given are simply preserved (not 3084 modified). Note that the ``description_i18n`` and ``taxes`` can only be 3085 modified in bulk: if it is given, all translations must be provided, not 3086 only those that changed. ``never`` should be used for the ``next_restock`` 3087 timestamp to indicate no intention/possibility of restocking, while a time 3088 of zero is used to indicate "unknown". 3089 3090 **Required permission:** ``products-write`` 3091 3092 **Request:** 3093 3094 The request must be a `ProductPatchDetail`. 3095 3096 **Response:** 3097 3098 :http:statuscode:`204 No content`: 3099 The backend has successfully expanded the inventory. 3100 :http:statuscode:`404 Not found`: 3101 The product (ID) is unknown to the backend. 3102 :http:statuscode:`409 Conflict`: 3103 The provided information is inconsistent with the current state of the inventory. 3104 3105 3106 .. ts:def:: ProductPatchDetail 3107 3108 interface ProductPatchDetail { 3109 3110 // Human-readable product name. 3111 // Since API version **v20**. Optional only for 3112 // backwards-compatibility, should be considered mandatory 3113 // moving forward! 3114 product_name?: string; 3115 3116 // Human-readable product description. 3117 description: string; 3118 3119 // Map from IETF BCP 47 language tags to localized descriptions. 3120 description_i18n?: { [lang_tag: string]: string }; 3121 3122 // Unit in which the product is measured (liters, kilograms, packages, etc.). 3123 unit: string; 3124 3125 // Optional override to control whether fractional quantities are permitted. 3126 unit_allow_fraction?: boolean; 3127 3128 // Override for the fractional precision level (0-6). Only relevant if 3129 // ``unit_allow_fraction`` is true. 3130 unit_precision_level?: Integer; 3131 3132 // Categories into which the product belongs. 3133 // Used in the POS-endpoint. 3134 // Since API version **v16**. 3135 categories?: Integer[]; 3136 3137 // Preferred way to express the per-unit price. Supply at least one entry; 3138 // the first entry represents the base price and MUST include applicable taxes. 3139 // Zero implies that the product is not sold separately or that the price must be supplied 3140 // by the frontend. 3141 unit_price?: Amount[]; 3142 3143 // Legacy price field. Deprecated; when present it must match the first element of ``unit_price``. 3144 price?: Amount; 3145 3146 // An optional base64-encoded product image. 3147 image?: ImageDataUrl; 3148 3149 // A list of taxes paid by the merchant for one unit of this product. 3150 taxes?: Tax[]; 3151 3152 // Preferred way to express inventory counts using "<integer>[.<fraction>]" syntax. 3153 // Use "-1" for unlimited stock. 3154 unit_total_stock?: string; 3155 3156 // Legacy stock counter. Deprecated, use ``unit_total_stock`` instead. 3157 total_stock?: Integer; 3158 3159 // Number of units of the product that were lost (spoiled, stolen, etc.). 3160 total_lost?: Integer; 3161 3162 // Identifies where the product is in stock. 3163 address?: Location; 3164 3165 // Identifies when we expect the next restocking to happen. 3166 next_restock?: Timestamp; 3167 3168 // Minimum age buyer must have (in years). Default is 0. 3169 minimum_age?: Integer; 3170 3171 } 3172 3173 The same compatibility rules for the ``unit_*`` fields and their deprecated counterparts apply 3174 when patching an existing product. 3175 3176 Inspecting inventory 3177 ^^^^^^^^^^^^^^^^^^^^ 3178 3179 .. http:get:: [/instances/$INSTANCE]/private/products 3180 3181 This is used to return the list of all items in the inventory. 3182 3183 **Required permission:** ``products-read`` 3184 3185 **Request:** 3186 3187 :query limit: *Optional*. At most return the given number of results. Negative for descending by row ID, positive for ascending by row ID. Default is ``20``. Since protocol **v12**. 3188 :query offset: *Optional*. Starting ``product_serial_id`` for an iteration. Since protocol **v12**. 3189 :query category_filter: *Optional*. Only returns products that are in a category where the category name contains the given text as a substring. Matching is case-insensitive. Since protocol **v23**. 3190 :query name_filter: *Optional*. Only returns products where the product name contains the given text as a substring. Matching is case-insensitive. Since protocol **v23**. 3191 :query description_filter: *Optional*. Only returns products where the product description contains the given text as a substring. Matching is case-insensitive. Since protocol **v23**. 3192 3193 **Response:** 3194 3195 :http:statuscode:`200 OK`: 3196 The backend has successfully returned the inventory. Returns 3197 a `InventorySummaryResponse`. 3198 :http:statuscode:`404 Not found`: 3199 The backend has does not know about the instance. 3200 3201 **Details:** 3202 3203 .. ts:def:: InventorySummaryResponse 3204 3205 interface InventorySummaryResponse { 3206 // List of products that are present in the inventory. 3207 products: InventoryEntry[]; 3208 } 3209 3210 The `InventoryEntry` object describes an item in the inventory. It has the following structure: 3211 3212 .. ts:def:: InventoryEntry 3213 3214 interface InventoryEntry { 3215 // Product identifier, as found in the product. 3216 product_id: string; 3217 3218 // ``product_serial_id`` of the product in the database. 3219 product_serial: Integer; 3220 3221 } 3222 3223 3224 .. http:get:: [/instances/$INSTANCE]/private/products/$PRODUCT_ID 3225 3226 This is used to obtain detailed information about a product in the inventory. 3227 3228 **Required permission:** ``products-read`` 3229 3230 **Response:** 3231 3232 :http:statuscode:`200 OK`: 3233 The backend has successfully returned the inventory. Returns 3234 a `ProductDetail`. 3235 :http:statuscode:`404 Not found`: 3236 The product (ID) is unknown to the backend. 3237 3238 **Details:** 3239 3240 .. ts:def:: ProductDetail 3241 3242 interface ProductDetail { 3243 3244 // Human-readable product name. 3245 // Since API version **v20**. 3246 product_name: string; 3247 3248 // Human-readable product description. 3249 description: string; 3250 3251 // Map from IETF BCP 47 language tags to localized descriptions. 3252 description_i18n: { [lang_tag: string]: string }; 3253 3254 // Unit in which the product is measured (liters, kilograms, packages, etc.). 3255 unit: string; 3256 3257 // Does the backend allow fractional quantities for this unit? 3258 unit_allow_fraction: boolean; 3259 3260 // Maximum fractional precision (0-6) enforced for inventory operations. 3261 unit_precision_level: Integer; 3262 3263 // Categories into which the product belongs. 3264 // Since API version **v16**. 3265 categories: Integer[]; 3266 3267 // Price tiers for this product. The first entry represents the base price and MUST include 3268 // applicable taxes. Zero implies the product is not sold separately or that the price is not 3269 // fixed, and must be supplied by the front-end. 3270 unit_price: Amount[]; 3271 3272 // Legacy price field kept for compatibility. Deprecated; equal to the first element of ``unit_price``. 3273 price: Amount; 3274 3275 // An optional base64-encoded product image. 3276 image: ImageDataUrl; 3277 3278 // A list of taxes paid by the merchant for one unit of this product. 3279 // Optional since **v15**. 3280 taxes?: Tax[]; 3281 3282 // Legacy integer stock counter kept for compatibility. ``-1`` indicates unlimited stock. 3283 total_stock: Integer; 3284 3285 // Stock expressed using "<integer>[.<fraction>]" syntax with up to six fractional digits. 3286 // Use ``"-1"`` for unlimited stock. 3287 unit_total_stock: string; 3288 3289 // Number of units of the product that have already been sold. 3290 total_sold: Integer; 3291 3292 // Number of units of the product that were lost (spoiled, stolen, etc.). 3293 total_lost: Integer; 3294 3295 // Identifies where the product is in stock. 3296 // Optional since **v15**. 3297 address?: Location; 3298 3299 // Identifies when we expect the next restocking to happen. 3300 next_restock?: Timestamp; 3301 3302 // Minimum age buyer must have (in years). 3303 minimum_age?: Integer; 3304 3305 } 3306 3307 .. http:get:: [/instances/$INSTANCE]/private/pos 3308 3309 This is used to return the point-of-sale (POS) configuration with full details on all items in the inventory. 3310 3311 Endpoint was introduced in protocol **v15**. 3312 3313 **Required permission:** ``products-read`` 3314 3315 **Response:** 3316 3317 :http:statuscode:`200 OK`: 3318 The backend has successfully returned the inventory. Returns 3319 a `FullInventoryDetailsResponse`. 3320 :http:statuscode:`404 Not found`: 3321 The backend has does not know about the instance. 3322 3323 **Details:** 3324 3325 .. ts:def:: FullInventoryDetailsResponse 3326 3327 interface FullInventoryDetailsResponse { 3328 3329 // List of products that are present in the inventory. 3330 products: MerchantPosProductDetail[]; 3331 3332 // List of categories in the inventory. 3333 categories: MerchantCategory[]; 3334 3335 } 3336 3337 .. ts:def:: MerchantPosProductDetail 3338 3339 interface MerchantPosProductDetail { 3340 3341 // A unique numeric ID of the product 3342 product_serial: Integer; 3343 3344 // A merchant-internal unique identifier for the product. 3345 product_id: string; 3346 3347 // Human-readable product name. 3348 // Since API version **v20**. 3349 product_name: string; 3350 3351 // A list of category IDs this product belongs to. 3352 // Typically, a product only belongs to one category, but more than one is supported. 3353 categories: Integer[]; 3354 3355 // Human-readable product description. 3356 description: string; 3357 3358 // Map from IETF BCP 47 language tags to localized descriptions. 3359 description_i18n: { [lang_tag: string]: string }; 3360 3361 // Unit in which the product is measured (liters, kilograms, packages, etc.). 3362 unit: string; 3363 3364 // Does the backend allow fractional quantities for this unit? 3365 unit_allow_fraction: boolean; 3366 3367 // Maximum fractional precision (0-6) enforced for inventory operations. 3368 unit_precision_level: Integer; 3369 3370 // Price tiers for this product. The first entry represents the base price and MUST include 3371 // applicable taxes. Zero implies the product is not sold separately or that the price is not 3372 // fixed, and must be supplied by the front-end. 3373 unit_price: Amount[]; 3374 3375 // Legacy price field kept for compatibility. Deprecated; equal to the first element of ``unit_price``. 3376 price: Amount; 3377 3378 // An optional base64-encoded product image. 3379 image?: ImageDataUrl; 3380 3381 // A list of taxes paid by the merchant for one unit of this product. 3382 taxes?: Tax[]; 3383 3384 // Legacy integer stock counter kept for compatibility. ``-1`` indicates unlimited stock. 3385 total_stock?: Integer; 3386 3387 // Stock expressed using "<integer>[.<fraction>]" syntax with up to six fractional digits. 3388 // Use ``"-1"`` for unlimited stock. 3389 unit_total_stock: string; 3390 3391 // Minimum age buyer must have (in years). 3392 minimum_age?: Integer; 3393 3394 } 3395 3396 .. ts:def:: MerchantCategory 3397 3398 interface MerchantCategory { 3399 // A unique numeric ID of the category 3400 id: Integer; 3401 3402 // The name of the category. This will be shown to users and used in the order summary. 3403 name: string; 3404 3405 // Map from IETF BCP 47 language tags to localized names 3406 name_i18n?: { [lang_tag: string]: string }; 3407 } 3408 3409 3410 Fetching product images 3411 ^^^^^^^^^^^^^^^^^^^^^^^ 3412 3413 .. http:get:: /products/$IMAGE_HASH/image 3414 3415 Returns a stored product image by its content hash. The hash is the lowercase 3416 hexadecimal SHA-256 digest of the base64-encoded image data supplied in 3417 ``image`` during product creation or update. 3418 3419 **Required permission:** none (public endpoint) 3420 3421 **Response:** 3422 3423 :http:statuscode:`200 OK`: 3424 The body is a `ProductImageResponse`. 3425 :http:statuscode:`400 Bad Request`: 3426 The hash is not a valid hex-encoded SHA-256 digest. 3427 :http:statuscode:`404 Not found`: 3428 No image is known for the given hash. 3429 3430 .. ts:def:: ProductImageResponse 3431 3432 interface ProductImageResponse { 3433 // Data URL containing the product image as stored in the backend. 3434 image: ImageDataUrl; 3435 } 3436 3437 3438 3439 Reserving inventory 3440 ^^^^^^^^^^^^^^^^^^^ 3441 3442 .. http:post:: [/instances/$INSTANCE]/private/products/$PRODUCT_ID/lock 3443 3444 This is used to lock a certain quantity of the product for a limited 3445 duration while the customer assembles a complete order. Note that 3446 frontends do not have to "unlock", they may rely on the timeout as 3447 given in the ``duration`` field. Re-posting a lock with a different 3448 ``duration`` or ``quantity`` updates the existing lock for the same UUID 3449 and does not result in a conflict. 3450 3451 Unlocking by using a ``quantity`` of zero is 3452 optional but recommended if customers remove products from the 3453 shopping cart. Note that actually POSTing to ``/orders`` with set 3454 ``inventory_products`` and using ``lock_uuids`` will **transition** the 3455 lock to the newly created order (which may have a different ``duration`` 3456 and ``quantity`` than what was requested in the lock operation). 3457 If an order is for fewer items than originally locked, the difference 3458 is automatically unlocked. 3459 3460 **Required permission:** ``products-lock`` 3461 3462 **Request:** 3463 3464 The request must be a `LockRequest`. 3465 3466 **Response:** 3467 3468 :http:statuscode:`204 No content`: 3469 The backend has successfully locked (or unlocked) the requested ``quantity``. 3470 :http:statuscode:`404 Not found`: 3471 The backend has does not know this product. 3472 :http:statuscode:`410 Gone`: 3473 The backend does not have enough of product in stock. Returns an `OutOfStockResponse`. 3474 3475 **Details:** 3476 3477 .. ts:def:: LockRequest 3478 3479 interface LockRequest { 3480 3481 // UUID that identifies the frontend performing the lock 3482 // Must be unique for the lifetime of the lock. 3483 lock_uuid: string; 3484 3485 // How long does the frontend intend to hold the lock? 3486 duration: RelativeTime; 3487 3488 // Legacy integer quantity to lock. Deprecated; defaults to 1 if both 3489 // ``quantity`` and ``unit_quantity`` are absent. 3490 quantity?: Integer; 3491 3492 // Preferred way to express the requested quantity using "<integer>[.<fraction>]" syntax. 3493 unit_quantity?: string; 3494 3495 } 3496 3497 At least one of ``quantity`` or ``unit_quantity`` must be supplied; omitting both defaults to a 3498 quantity of one. ``unit_quantity`` follows the same decimal-string format described for 3499 ``unit_total_stock``. 3500 3501 .. note:: 3502 3503 The ``GNUNET_CRYPTO_random_timeflake()`` C API can be used 3504 to generate such timeflakes for clients written in C. 3505 3506 3507 Removing products from inventory 3508 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 3509 3510 .. http:delete:: [/instances/$INSTANCE]/private/products/$PRODUCT_ID 3511 3512 Delete information about a product. Fails if the product is locked by 3513 anyone. 3514 3515 **Required permission:** ``products-write`` 3516 3517 **Response:** 3518 3519 :http:statuscode:`204 No content`: 3520 The backend has successfully deleted the product. 3521 :http:statuscode:`404 Not found`: 3522 The backend does not know the instance or the product. 3523 :http:statuscode:`409 Conflict`: 3524 The backend refuses to delete the product because it is locked. 3525 3526 3527 ------------------ 3528 Payment processing 3529 ------------------ 3530 3531 To process Taler payments, a merchant must first set up an order with 3532 the merchant backend. The order is then claimed by a wallet, and 3533 paid by the wallet. The merchant can check the payment status of the 3534 order. Once the order is paid, the merchant may (for a limited time) 3535 grant refunds on the order. 3536 3537 Creating orders 3538 ^^^^^^^^^^^^^^^ 3539 3540 .. _post-order: 3541 3542 .. http:post:: [/instances/$INSTANCE]/private/orders 3543 3544 Create a new order that a customer can pay for. 3545 3546 This request is **not** idempotent unless an ``order_id`` is explicitly specified. 3547 However, while repeating without an ``order_id`` will create another order, that is 3548 generally pretty harmless (as long as only one of the orders is returned to the wallet). 3549 3550 .. note:: 3551 3552 This endpoint does not return a URL to redirect your user to confirm the 3553 payment. To get this URL use either 3554 :http:get:`[/instances/$INSTANCE]/orders/$ORDER_ID` (with 3555 ``taler_pay_uri`` in the `StatusUnpaidResponse`), or 3556 :http:get:`[/instances/$INSTANCE]/private/orders/$ORDER_ID` with the 3557 ``taler_pay_uri`` in the `CheckPaymentUnpaidResponse`). That said, 3558 it is also possible to construct the URL by combining the base URL 3559 with the information from the `PostOrderResponse`. 3560 The API is structured this way since the payment redirect URL is not 3561 unique for every order: there might be varying parameters such as the 3562 session id. 3563 3564 **Required permission:** ``orders-write`` 3565 3566 **Request:** 3567 3568 The request must be a `PostOrderRequest`. 3569 3570 **Response:** 3571 3572 :http:statuscode:`200 OK`: 3573 The backend has successfully created the proposal. The response is a 3574 :ts:type:`PostOrderResponse`. 3575 :http:statuscode:`404 Not found`: 3576 Possible reasons are: 3577 3578 (1) The order given used products from the inventory, but those were 3579 not found in the inventory. 3580 (2) The merchant instance is unknown (including possibly the instance 3581 being not configured for new orders). 3582 (3) The wire method specified is not supported by the backend. 3583 (4) An OTP device ID was specified and is unknown. 3584 3585 Details in the error code. 3586 NOTE: currently the client has no good way to find out which product 3587 is not in the inventory, we MAY want to specify that in the reply. 3588 :http:statuscode:`409 Conflict`: 3589 A different proposal already exists under the specified order ID, 3590 or the requested currency is not supported by this backend. Details in 3591 the error code. 3592 :http:statuscode:`410 Gone`: 3593 The order given used products from the inventory that are out of stock. 3594 The response is a :ts:type:`OutOfStockResponse`. 3595 :http:statuscode:`451 Unavailable for Legal Reasons`: 3596 The order could not be created because of legal 3597 reasons, specifically no exchange would accept 3598 a payment at this time because we have not yet 3599 satisfied the respective legal requirements. 3600 The :ref:`KYC status <merchantkycstatus>` API 3601 can be used to determine details about how to 3602 proceed with the KYC process. 3603 The body is a `PaymentDeniedLegallyResponse` with 3604 details about the exchange(s) causing the failure. 3605 Since protocol **v17**. 3606 3607 **Details:** 3608 3609 .. ts:def:: PostOrderRequest 3610 3611 interface PostOrderRequest { 3612 // The order must at least contain the minimal 3613 // order detail, but can override all. 3614 order: Order; 3615 3616 // If set, the backend will then set the refund deadline to the 3617 // payment deadline plus the specified delay. 3618 // If it's not set, the default value of the backend might be 3619 // used. Note that both this value and the backend default 3620 // will be ignored if ``refund_deadline`` is set in ``order`` 3621 // as the ``refund_deadline`` takes precedence. 3622 // A value of "forever" is not allowed. 3623 refund_delay?: RelativeTime; 3624 3625 // Specifies the payment target preferred by the client. Can be used 3626 // to select among the various (active) wire methods supported by the instance. 3627 payment_target?: string; 3628 3629 // The session for which the payment is made (or replayed). 3630 // Only set for session-based payments. 3631 // Since protocol **v6**. 3632 session_id?: string; 3633 3634 // Specifies that some products are to be included in the 3635 // order from the inventory. For these inventory management 3636 // is performed (so the products must be in stock) and 3637 // details are completed from the product data of the backend. 3638 inventory_products?: MinimalInventoryProduct[]; 3639 3640 // Specifies a lock identifier that was used to 3641 // lock a product in the inventory. Only useful if 3642 // ``inventory_products`` is set. Used in case a frontend 3643 // reserved quantities of the individual products while 3644 // the shopping cart was being built. Multiple UUIDs can 3645 // be used in case different UUIDs were used for different 3646 // products (i.e. in case the user started with multiple 3647 // shopping sessions that were combined during checkout). 3648 lock_uuids?: string[]; 3649 3650 // Should a token for claiming the order be generated? 3651 // False can make sense if the ORDER_ID is sufficiently 3652 // high entropy to prevent adversarial claims (like it is 3653 // if the backend auto-generates one). Default is 'true'. 3654 // Note: This is NOT related to tokens used for subscriptins or discounts. 3655 create_token?: boolean; 3656 3657 // OTP device ID to associate with the order. 3658 // This parameter is optional. 3659 otp_id?: string; 3660 } 3661 3662 The `Order` object represents the starting point for new `ContractTerms`. 3663 After validating and sanatizing all inputs, the merchant backend will add 3664 additional information to the order and create a new `ContractTerms` object 3665 that will be stored in the database. 3666 3667 .. ts:def:: Order 3668 3669 type Order = (OrderV1 | OrderV0) & OrderCommon; 3670 3671 .. ts:def:: OrderV1 3672 3673 interface OrderV1 { 3674 // Version 1 order support discounts and subscriptions. 3675 // https://docs.taler.net/design-documents/046-mumimo-contracts.html 3676 // @since protocol **v21** 3677 version: 1; 3678 3679 // List of contract choices that the customer can select from. 3680 // @since protocol **v21** 3681 choices?: OrderChoice[]; 3682 } 3683 3684 .. ts:def:: OrderV0 3685 3686 interface OrderV0 { 3687 // Optional, defaults to 0 if not set. 3688 version?: 0; 3689 3690 // Total price for the transaction. The exchange will subtract deposit 3691 // fees from that amount before transferring it to the merchant. 3692 amount: Amount; 3693 3694 // Maximum total deposit fee accepted by the merchant for this contract. 3695 // Overrides defaults of the merchant instance. 3696 max_fee?: Amount; 3697 } 3698 3699 .. ts:def:: OrderCommon 3700 3701 interface OrderCommon { 3702 // Human-readable description of the whole purchase. 3703 summary: string; 3704 3705 // Map from IETF BCP 47 language tags to localized summaries. 3706 summary_i18n?: { [lang_tag: string]: string }; 3707 3708 // Unique identifier for the order. Only characters 3709 // allowed are "A-Za-z0-9" and ".:_-". 3710 // Must be unique within a merchant instance. 3711 // For merchants that do not store proposals in their DB 3712 // before the customer paid for them, the ``order_id`` can be used 3713 // by the frontend to restore a proposal from the information 3714 // encoded in it (such as a short product identifier and timestamp). 3715 order_id?: string; 3716 3717 // URL where the same contract could be ordered again (if 3718 // available). Returned also at the public order endpoint 3719 // for people other than the actual buyer (hence public, 3720 // in case order IDs are guessable). 3721 public_reorder_url?: string; 3722 3723 // See documentation of ``fulfillment_url`` field in `ContractTerms`. 3724 // Either fulfillment_url or fulfillment_message must be specified. 3725 // When creating an order, the fulfillment URL can 3726 // contain ``${ORDER_ID}`` which will be substituted with the 3727 // order ID of the newly created order. 3728 fulfillment_url?: string; 3729 3730 // See documentation of ``fulfillment_message`` in `ContractTerms`. 3731 // Either ``fulfillment_url`` or ``fulfillment_message`` must be specified. 3732 fulfillment_message?: string; 3733 3734 // Map from IETF BCP 47 language tags to localized fulfillment 3735 // messages. 3736 fulfillment_message_i18n?: { [lang_tag: string]: string }; 3737 3738 // Minimum age the buyer must have to buy. 3739 minimum_age?: Integer; 3740 3741 // List of products that are part of the purchase. 3742 products?: Product[]; 3743 3744 // Time when this contract was generated. If null, defaults to current 3745 // time of merchant backend. 3746 timestamp?: Timestamp; 3747 3748 // After this deadline has passed, no refunds will be accepted. 3749 // Overrides deadline calculated from ``refund_delay`` in 3750 // ``PostOrderRequest``. 3751 // A value of "never" is not allowed. 3752 refund_deadline?: Timestamp; 3753 3754 // After this deadline, the merchant won't accept payments for the contract. 3755 // Overrides deadline calculated from default pay delay configured in 3756 // merchant backend. 3757 // A value of "never" is not allowed. 3758 pay_deadline?: Timestamp; 3759 3760 // Transfer deadline for the exchange. Must be in the deposit permissions 3761 // of coins used to pay for this order. 3762 // Overrides deadline calculated from default wire transfer delay 3763 // configured in merchant backend. Must be after refund deadline. 3764 // A value of "never" is not allowed. 3765 wire_transfer_deadline?: Timestamp; 3766 3767 // Base URL of the (public!) merchant backend API. 3768 // Must be an absolute URL that ends with a slash. 3769 // Defaults to the base URL this request was made to. 3770 merchant_base_url?: string; 3771 3772 // Delivery location for (all!) products. 3773 delivery_location?: Location; 3774 3775 // Time indicating when the order should be delivered. 3776 // May be overwritten by individual products. 3777 // Must be in the future. 3778 delivery_date?: Timestamp; 3779 3780 // See documentation of ``auto_refund`` in ``ContractTerms``. 3781 // Specifies for how long the wallet should try to get an 3782 // automatic refund for the purchase. 3783 auto_refund?: RelativeTime; 3784 3785 // Extra data that is only interpreted by the merchant frontend. 3786 // Useful when the merchant needs to store extra information on a 3787 // contract without storing it separately in their database. 3788 // Must really be an Object (not a string, integer, float or array). 3789 extra?: Object; 3790 } 3791 3792 3793 The `OrderChoice` object describes a possible choice within an order. The 3794 choice is done by the wallet and consists of in- and outputs. In the example 3795 of buying an article, the merchant could present the customer with the 3796 choice to use a valid subscription token or pay using a gift 3797 voucher. Available since protocol **v21**. 3798 3799 .. ts:def:: OrderChoice 3800 3801 interface OrderChoice { 3802 // Total price for the choice. The exchange will subtract deposit 3803 // fees from that amount before transferring it to the merchant. 3804 amount: Amount; 3805 3806 // Human readable description of the semantics of the choice 3807 // within the contract to be shown to the user at payment. 3808 description?: string; 3809 3810 // Map from IETF 47 language tags to localized descriptions. 3811 description_i18n?: { [lang_tag: string]: string }; 3812 3813 // Inputs that must be provided by the customer, if this choice is selected. 3814 // Defaults to empty array if not specified. 3815 inputs?: OrderInput[]; 3816 3817 // Outputs provided by the merchant, if this choice is selected. 3818 // Defaults to empty array if not specified. 3819 outputs?: OrderOutput[]; 3820 3821 // Maximum total deposit fee accepted by the merchant for this contract. 3822 // Overrides defaults of the merchant instance. 3823 max_fee?: Amount; 3824 } 3825 3826 .. ts:def:: OrderInput 3827 3828 // For now, only token inputs are supported. 3829 type OrderInput = OrderInputToken; 3830 3831 .. ts:def:: OrderInputToken 3832 3833 interface OrderInputToken { 3834 3835 // Token input. 3836 type: "token"; 3837 3838 // Token family slug as configured in the merchant backend. Slug is unique 3839 // across all configured tokens of a merchant. 3840 token_family_slug: string; 3841 3842 // How many units of the input are required. 3843 // Defaults to 1 if not specified. Output with count == 0 are ignored by 3844 // the merchant backend. 3845 count?: Integer; 3846 3847 } 3848 3849 .. ts:def:: OrderOutput 3850 3851 type OrderOutput = OrderOutputToken | OrderOutputTaxReceipt; 3852 3853 .. ts:def:: OrderOutputToken 3854 3855 interface OrderOutputToken { 3856 3857 // Token output. 3858 type: "token"; 3859 3860 // Token family slug as configured in the merchant backend. Slug is unique 3861 // across all configured tokens of a merchant. 3862 token_family_slug: string; 3863 3864 // How many units of the output are issued by the merchant. 3865 // Defaults to 1 if not specified. Output with count == 0 are ignored by 3866 // the merchant backend. 3867 count?: Integer; 3868 3869 // When should the output token be valid. Can be specified if the 3870 // desired validity period should be in the future (like selling 3871 // a subscription for the next month). Optional. If not given, 3872 // the validity is supposed to be "now" (time of order creation). 3873 valid_at?: Timestamp; 3874 3875 } 3876 3877 .. ts:def:: OrderOutputTaxReceipt 3878 3879 interface OrderOutputTaxReceipt { 3880 3881 // Tax receipt output. 3882 type: "tax-receipt"; 3883 3884 } 3885 3886 The following `MinimalInventoryProduct` can be provided if the parts of the 3887 order are inventory-based, that is if the `PostOrderRequest` uses 3888 ``inventory_products``. For such products, which must be in the backend's inventory, 3889 the backend can automatically fill in the amount and other details about 3890 the product that are known to it from its ``products`` table. 3891 Note that the ``inventory_products`` will be appended to the 3892 list of ``products`` that the frontend already put into the ``order``. 3893 So if the frontend can sell additional non-inventory products together 3894 with ``inventory_products``. Note that the backend will NOT update 3895 the ``amount`` of the ``order``, so the frontend must already have calculated 3896 the total price --- including the ``inventory_products``. 3897 3898 .. ts:def:: MinimalInventoryProduct 3899 3900 // Note that if the frontend does give details beyond these, 3901 // it will override those details (including price or taxes) 3902 // that the backend would otherwise fill in via the inventory. 3903 interface MinimalInventoryProduct { 3904 3905 // Which product is requested (here mandatory!). 3906 product_id: string; 3907 3908 // Legacy integer quantity. Deprecated; defaults to 1 if both 3909 // ``quantity`` and ``unit_quantity`` are absent. 3910 quantity?: Integer; 3911 3912 // Preferred quantity string using "<integer>[.<fraction>]" syntax. 3913 unit_quantity?: string; 3914 } 3915 3916 Supply either ``quantity`` or ``unit_quantity`` when referencing inventory products. If both are 3917 missing the backend assumes a quantity of one. ``unit_quantity`` follows the same decimal-string 3918 rules as ``unit_total_stock``. 3919 3920 .. ts:def:: PostOrderResponse 3921 3922 interface PostOrderResponse { 3923 // Order ID of the response that was just created. 3924 order_id: string; 3925 3926 // Deadline when the offer expires; the customer must pay before. 3927 // @since protocol **v21**. 3928 pay_deadline: Timestamp; 3929 3930 // Token that authorizes the wallet to claim the order. 3931 // Provided only if "create_token" was set to 'true' 3932 // in the request. 3933 token?: ClaimToken; 3934 } 3935 3936 .. ts:def:: OutOfStockResponse 3937 3938 interface OutOfStockResponse { 3939 3940 // Product ID of an out-of-stock item. 3941 product_id: string; 3942 3943 // Legacy integer quantity requested. Deprecated; see ``unit_requested_quantity``. 3944 requested_quantity: Integer; 3945 3946 // Requested quantity using "<integer>[.<fraction>]" syntax with up to six fractional digits. 3947 unit_requested_quantity: string; 3948 3949 // Legacy integer availability (must be below ``requested_quantity``). 3950 available_quantity: Integer; 3951 3952 // Available quantity using "<integer>[.<fraction>]" syntax with up to six fractional digits. 3953 unit_available_quantity: string; 3954 3955 // When do we expect the product to be again in stock? 3956 // Optional, not given if unknown. 3957 restock_expected?: Timestamp; 3958 } 3959 3960 3961 Inspecting orders 3962 ^^^^^^^^^^^^^^^^^ 3963 3964 .. http:get:: [/instances/$INSTANCE]/private/orders 3965 3966 Returns known orders up to some point in the past. 3967 3968 **Required permission:** ``orders-read`` 3969 3970 **Request:** 3971 3972 :query paid: *Optional*. If set to yes, only return paid orders, if no only unpaid orders. Do not give (or use "all") to see all orders regardless of payment status. 3973 :query refunded: *Optional*. If set to yes, only return refunded orders, if no only unrefunded orders. Do not give (or use "all") to see all orders regardless of refund status. 3974 :query wired: *Optional*. If set to yes, only return wired orders, if no only orders with missing wire transfers. Do not give (or use "all") to see all orders regardless of wire transfer status. 3975 :query delta: *Optional*. takes value of the form ``N (-N)``, so that at most ``N`` values strictly older (younger) than ``start`` and ``date_s`` are returned. Defaults to ``-20`` to return the last 20 entries (before ``start`` and/or ``date_s``). Deprecated in protocol **v12**. Use *limit* instead. 3976 :query limit: *Optional*. At most return the given number of results. Negative for descending by row ID, positive for ascending by row ID. Default is ``20``. Since protocol **v12**. 3977 :query date_s: *Optional.* Non-negative date in seconds after the UNIX Epoc, see ``delta`` for its interpretation. If not specified, we default to the oldest or most recent entry, depending on ``limit``. 3978 :query start: *Optional*. Row number threshold, see ``limit`` for its interpretation. Defaults to ``INT64_MAX``, namely the biggest row id possible in the database. Deprecated in protocol **v12**. Use *offset* instead. 3979 :query offset: *Optional*. Starting ``row_id`` for an iteration. Since protocol **v12**. 3980 :query timeout_ms: *Optional*. Timeout in milliseconds to wait for additional orders if the answer would otherwise be negative (long polling). Only useful if ``limit`` is positive. Note that the merchant MAY still return a response that contains fewer than ``limit`` orders. 3981 :query session_id: *Optional*. Since protocol **v6**. Filters by session ID. 3982 :query fulfillment_url: *Optional*. Since protocol **v6**. Filters by fulfillment URL. 3983 :query summary_filter: *Optional*. Only returns orders where the summary contains the given text as a substring. Matching is case-insensitive. Since protocol **v23**. 3984 3985 **Response:** 3986 3987 :http:statuscode:`200 OK`: 3988 The response is an `OrderHistory`. 3989 3990 **Details:** 3991 3992 .. ts:def:: OrderHistory 3993 3994 interface OrderHistory { 3995 // Timestamp-sorted array of all orders matching the query. 3996 // The order of the sorting depends on the sign of ``limit``. 3997 orders : OrderHistoryEntry[]; 3998 } 3999 4000 4001 .. ts:def:: OrderHistoryEntry 4002 4003 interface OrderHistoryEntry { 4004 4005 // Order ID of the transaction related to this entry. 4006 order_id: string; 4007 4008 // Row ID of the order in the database. 4009 row_id: Integer; 4010 4011 // When the order was created. 4012 timestamp: Timestamp; 4013 4014 // The amount of money the order is for. If the contract 4015 // has multiple choices and the user has not yet made a choice, 4016 // we return the amount of the first choice. 4017 amount: Amount; 4018 4019 // The total amount of refunds granted by the merchant. 4020 // Includes refunds that the wallet did not yet pick up. 4021 // Only available if the order was paid. 4022 // Since **v24**. 4023 refund_amount: Amount; 4024 4025 // The amount of refunds the customer's wallet did not yet 4026 // pick up. Only available if the order was paid. 4027 // Since **v24**. 4028 pending_refund_amount: Amount; 4029 4030 // The summary of the order. 4031 summary: string; 4032 4033 // Whether some part of the order is refundable, 4034 // that is the refund deadline has not yet expired 4035 // and the total amount refunded so far is below 4036 // the value of the original transaction. 4037 refundable: boolean; 4038 4039 // Whether the order has been paid or not. 4040 paid: boolean; 4041 } 4042 4043 .. http:get:: [/instances/$INSTANCE]/private/orders/$ORDER_ID 4044 4045 Merchant checks the payment status of an order. If the order exists but is not paid 4046 and not claimed yet, the response provides a redirect URL. When the user goes to this URL, 4047 they will be prompted for payment. Differs from the ``public`` API both 4048 in terms of what information is returned and in that the wallet must provide 4049 the contract hash to authenticate, while for this API we assume that the 4050 merchant is authenticated (as the endpoint is not ``public``). 4051 4052 **Required permission:** ``orders-read`` 4053 4054 **Request:** 4055 4056 :query session_id: *Optional*. Session ID that the payment must be bound to. If not specified, the payment is not session-bound. 4057 :query transfer: Deprecated in protocol **V6**. *Optional*. If set to "YES", try to obtain the wire transfer status for this order from the exchange. Otherwise, the wire transfer status MAY be returned if it is available. 4058 :query timeout_ms: *Optional*. Timeout in milliseconds to wait for a payment if the answer would otherwise be negative (long polling). 4059 :query allow_refunded_for_repurchase: *Optional*. Since protocol **v9** refunded orders are only returned under "already_paid_order_id" if this flag is set explicitly to "YES". 4060 4061 **Response:** 4062 4063 :http:statuscode:`200 OK`: 4064 Returns a `MerchantOrderStatusResponse`, whose format can differ based on the status of the payment. 4065 :http:statuscode:`404 Not found`: 4066 The order or instance is unknown to the backend. Error code 4067 is set to either ``MERCHANT_GENERIC_ORDER_UNKNOWN`` or 4068 ``MERCHANT_GENERIC_INSTANCE_UNKNOWN``. 4069 4070 **Details:** 4071 4072 .. ts:def:: MerchantOrderStatusResponse 4073 4074 type MerchantOrderStatusResponse = CheckPaymentPaidResponse | 4075 CheckPaymentClaimedResponse | 4076 CheckPaymentUnpaidResponse; 4077 4078 .. ts:def:: CheckPaymentPaidResponse 4079 4080 interface CheckPaymentPaidResponse { 4081 // The customer paid for this contract. 4082 order_status: "paid"; 4083 4084 // Was the payment refunded (even partially)? 4085 refunded: boolean; 4086 4087 // True if there are any approved refunds that the wallet has 4088 // not yet obtained. 4089 refund_pending: boolean; 4090 4091 // Did the exchange wire us the funds? 4092 wired: boolean; 4093 4094 // Total amount the exchange deposited into our bank account 4095 // for this contract, excluding fees. 4096 deposit_total: Amount; 4097 4098 // Numeric `error code <error-codes>` indicating errors the exchange 4099 // encountered tracking the wire transfer for this purchase (before 4100 // we even got to specific coin issues). 4101 // 0 if there were no issues. 4102 exchange_code: Integer; 4103 4104 // HTTP status code returned by the exchange when we asked for 4105 // information to track the wire transfer for this purchase. 4106 // 0 if there were no issues. 4107 exchange_http_status: Integer; 4108 4109 // Total amount that was refunded, 0 if refunded is false. 4110 refund_amount: Amount; 4111 4112 // Contract terms. 4113 contract_terms: ContractTerms; 4114 4115 // Index of the selected choice within the ``choices`` array of 4116 // ``contract terms``. 4117 // @since protocol **v21** 4118 choice_index?: Integer; 4119 4120 // If the order is paid, set to the last time when a payment 4121 // was made to pay for this order. @since **v14**. 4122 last_payment: Timestamp; 4123 4124 // The wire transfer status from the exchange for this order if 4125 // available, otherwise empty array. 4126 wire_details: TransactionWireTransfer[]; 4127 4128 // Reports about trouble obtaining wire transfer details, 4129 // empty array if no trouble were encountered. 4130 // @deprecated in protocol **v6**. 4131 wire_reports: TransactionWireReport[]; 4132 4133 // The refund details for this order. One entry per 4134 // refunded coin; empty array if there are no refunds. 4135 refund_details: RefundDetails[]; 4136 4137 // Status URL, can be used as a redirect target for the browser 4138 // to show the order QR code / trigger the wallet. 4139 order_status_url: string; 4140 } 4141 4142 .. ts:def:: CheckPaymentClaimedResponse 4143 4144 interface CheckPaymentClaimedResponse { 4145 // A wallet claimed the order, but did not yet pay for the contract. 4146 order_status: "claimed"; 4147 4148 // Contract terms. 4149 contract_terms: ContractTerms; 4150 4151 // Status URL, can be used as a redirect target for the browser 4152 // to show the order QR code / trigger the wallet. 4153 // Since protocol **v19**. 4154 order_status_url: string; 4155 } 4156 4157 .. ts:def:: CheckPaymentUnpaidResponse 4158 4159 interface CheckPaymentUnpaidResponse { 4160 // The order was neither claimed nor paid. 4161 order_status: "unpaid"; 4162 4163 // URI that the wallet must process to complete the payment. 4164 taler_pay_uri: string; 4165 4166 // Time when the order was created. 4167 creation_time: Timestamp; 4168 4169 // Deadline when the offer expires; the customer must pay before. 4170 // @since protocol **v21**. 4171 pay_deadline: Timestamp; 4172 4173 // Order summary text. 4174 summary: string; 4175 4176 // Total amount of the order (to be paid by the customer). 4177 // Will be undefined for unpaid v1 orders 4178 total_amount?: Amount; 4179 4180 // Alternative order ID which was paid for already in the same session. 4181 // Only given if the same product was purchased before in the same session. 4182 already_paid_order_id?: string; 4183 4184 // Fulfillment URL of an already paid order. Only given if under this 4185 // session an already paid order with a fulfillment URL exists. 4186 already_paid_fulfillment_url?: string; 4187 4188 // Status URL, can be used as a redirect target for the browser 4189 // to show the order QR code / trigger the wallet. 4190 order_status_url: string; 4191 4192 // We do we NOT return the contract terms here because they may not 4193 // exist in case the wallet did not yet claim them. 4194 } 4195 4196 .. ts:def:: RefundDetails 4197 4198 interface RefundDetails { 4199 // Reason given for the refund. 4200 reason: string; 4201 4202 // True if a refund is still available for the wallet for this payment. 4203 pending: boolean; 4204 4205 // When was the refund approved with a POST to 4206 // [/instances/$INSTANCE]/private/orders/$ORDER_ID/refund 4207 timestamp: Timestamp; 4208 4209 // Total amount that was refunded (minus a refund fee). 4210 amount: Amount; 4211 } 4212 4213 .. ts:def:: TransactionWireTransfer 4214 4215 interface TransactionWireTransfer { 4216 // Responsible exchange. 4217 exchange_url: string; 4218 4219 // 32-byte wire transfer identifier. 4220 wtid: Base32; 4221 4222 // Execution time of the wire transfer. 4223 execution_time: Timestamp; 4224 4225 // Total amount that has been wire transferred 4226 // to the merchant. 4227 amount: Amount; 4228 4229 // Was this transfer confirmed by the merchant via the 4230 // POST /transfers API, or is it merely claimed by the exchange? 4231 confirmed: boolean; 4232 } 4233 4234 .. ts:def:: TransactionWireReport 4235 4236 interface TransactionWireReport { 4237 // Numerical `error code <error-codes>`. 4238 code: Integer; 4239 4240 // Human-readable error description. 4241 hint: string; 4242 4243 // Numerical `error code <error-codes>` from the exchange. 4244 exchange_code: Integer; 4245 4246 // HTTP status code received from the exchange. 4247 exchange_http_status: Integer; 4248 4249 // Public key of the coin for which we got the exchange error. 4250 coin_pub: CoinPublicKey; 4251 } 4252 4253 4254 4255 .. _private-order-data-cleanup: 4256 4257 Private order data cleanup 4258 ^^^^^^^^^^^^^^^^^^^^^^^^^^ 4259 4260 Some orders may contain sensitive information that the merchant may not want 4261 to retain after fulfillment, such as the customer's shipping address. By 4262 initially labeling these order components as forgettable, the merchant can 4263 later tell the backend to forget those details (without changing the hash of 4264 the contract!) to minimize risks from information leakage. 4265 4266 4267 .. http:patch:: [/instances/$INSTANCE]/private/orders/$ORDER_ID/forget 4268 4269 Forget fields in an order's contract terms that the merchant no 4270 longer needs. 4271 4272 **Required permission:** ``orders-write`` 4273 4274 **Request:** 4275 4276 The request must be a `forget request <ForgetRequest>`. The fields specified 4277 must have been marked as forgettable when the contract was created. Fields in 4278 the request that are not in the `contract terms <ContractTerms>` are ignored. 4279 4280 A valid 4281 JSON path is defined as a string beginning with ``$.`` that follows the dot 4282 notation: ``$.wire_fee``, for example. The ``$`` represents the `contract terms <ContractTerms>` 4283 object, and an identifier following a ``.`` represents the field of that 4284 identifier belonging to the object preceding the dot. Arrays can be indexed 4285 by an non-negative integer within brackets: ``$.products[1]``. An asterisk ``*`` 4286 can be used to index an array as a wildcard, which expands the path into a 4287 list of paths containing one path for 4288 each valid array index: ``$.products[*].description``. For a path to be valid, 4289 it must end with a reference to a field of an object (it cannot end with an 4290 array index or wildcard). 4291 4292 **Response:** 4293 4294 :http:statuscode:`200 OK`: 4295 The merchant deleted the specified fields from the contract of 4296 order $ORDER_ID. 4297 :http:statuscode:`204 No content`: 4298 The merchant had already deleted the specified fields 4299 from the contract of order $ORDER_ID. 4300 :http:statuscode:`400 Bad request`: 4301 The request is malformed or one of the paths is invalid. 4302 :http:statuscode:`404 Not found`: 4303 The merchant backend could not find the order or the instance 4304 and thus cannot process the forget request. 4305 :http:statuscode:`409 Conflict`: 4306 The request includes a field that was not marked as forgettable, so 4307 the merchant cannot delete that field. 4308 4309 **Details:** 4310 4311 .. ts:def:: ForgetRequest 4312 4313 interface ForgetRequest { 4314 4315 // Array of valid JSON paths to forgettable fields in the order's 4316 // contract terms. 4317 fields: string[]; 4318 } 4319 4320 4321 .. http:delete:: [/instances/$INSTANCE]/private/orders/$ORDER_ID 4322 4323 Delete information about an order. Fails if the order was paid in the 4324 last 10 years (or whatever ``TAX_RECORD_EXPIRATION`` is set to) or was 4325 claimed but is unpaid and thus still a valid offer. 4326 4327 **Response:** 4328 4329 :http:statuscode:`204 No content`: 4330 The backend has successfully deleted the order. 4331 :http:statuscode:`404 Not found`: 4332 The backend does not know the instance or the order. 4333 :http:statuscode:`409 Conflict`: 4334 The backend refuses to delete the order. 4335 4336 4337 .. _merchant_refund: 4338 4339 ----------------- 4340 Approving Refunds 4341 ----------------- 4342 4343 .. http:post:: [/instances/$INSTANCE]/private/orders/$ORDER_ID/refund 4344 4345 Increase the refund amount associated with a given order. The user should be 4346 redirected to the ``taler_refund_uri`` to trigger refund processing in the wallet. 4347 4348 **Required permission:** ``orders-refund`` 4349 4350 **Request:** 4351 4352 The request body is a `RefundRequest` object. 4353 4354 **Response:** 4355 4356 :http:statuscode:`200 OK`: 4357 The refund amount has been increased, the backend 4358 responds with a `MerchantRefundResponse`. 4359 :http:statuscode:`403 Forbidden`: 4360 For the given order, the refund delay was zero and thus 4361 refunds are categorically not allowed. 4362 :http:statuscode:`404 Not found`: 4363 The order is unknown to the merchant. 4364 :http:statuscode:`410 Gone`: 4365 It is too late for aborting, the exchange may have already wired the funds 4366 to the merchant. 4367 :http:statuscode:`409 Conflict`: 4368 The refund amount exceeds the amount originally paid. 4369 :http:statuscode:`451 Unavailable for Legal Reasons`: 4370 The refund could not be awarded because of legal 4371 reasons (an exchange would refuse). The merchant 4372 staff needs to find another way to give a refund 4373 to the customer. 4374 The body is a `PaymentDeniedLegallyResponse` with 4375 details about the exchange causing the failure. 4376 Since protocol **v17**. 4377 4378 **Details:** 4379 4380 .. ts:def:: RefundRequest 4381 4382 interface RefundRequest { 4383 // Amount to be refunded. 4384 refund: Amount; 4385 4386 // Human-readable refund justification. 4387 reason: string; 4388 } 4389 4390 .. ts:def:: MerchantRefundResponse 4391 4392 interface MerchantRefundResponse { 4393 4394 // URL (handled by the backend) that the wallet should access to 4395 // trigger refund processing. 4396 // taler://refund/... 4397 taler_refund_uri: string; 4398 4399 // Contract hash that a client may need to authenticate an 4400 // HTTP request to obtain the above URI in a wallet-friendly way. 4401 h_contract: HashCode; 4402 } 4403 4404 4405 ----------------------- 4406 Tracking Wire Transfers 4407 ----------------------- 4408 4409 This API is used by merchants that want to track the payments from the 4410 exchange to be sure that they have been paid on time. By telling the merchant 4411 backend about all incoming wire transfers, the backend can detect if an 4412 exchange failed to perform a wire transfer that was due. 4413 4414 4415 Informing the backend about incoming wire transfers 4416 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 4417 4418 .. http:post:: [/instances/$INSTANCE]/private/transfers 4419 4420 Inform the backend over an incoming wire transfer. The backend should inquire about the details with the exchange and mark the respective orders as wired. Note that the request will fail if the WTID is not unique (which should be guaranteed by a correct exchange). 4421 This request is idempotent and should also be used to merely re-fetch the 4422 transfer information from the merchant's database (assuming we got a non-error 4423 response from the exchange before). 4424 4425 **Required permission:** ``transfers-write`` 4426 4427 **Request:** 4428 4429 The request must provide `transfer information <TransferInformation>`. 4430 4431 **Response:** 4432 4433 :http:statuscode:`204 No content`: 4434 The wire transfer is now confirmed at the merchant. 4435 :http:statuscode:`404 Not found`: 4436 The instance or account are unknown to the exchange. 4437 :http:statuscode:`409 Conflict`: 4438 The wire transfer identifier is already known to us, but for a different amount. 4439 4440 **Details:** 4441 4442 .. ts:def:: TransferInformation 4443 4444 interface TransferInformation { 4445 // How much was wired to the merchant (minus fees). 4446 credit_amount: Amount; 4447 4448 // Raw wire transfer identifier identifying the wire transfer (a base32-encoded value). 4449 wtid: WireTransferIdentifierRawP; 4450 4451 // Full payto://-URI of the bank account that received the wire transfer. 4452 payto_uri: string; 4453 4454 // Base URL of the exchange that made the wire transfer. 4455 exchange_url: string; 4456 } 4457 4458 4459 Querying known wire transfers 4460 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 4461 4462 .. http:get:: [/instances/$INSTANCE]/private/transfers 4463 4464 Obtain a list of all wire transfers the backend was told 4465 had been made into the merchant bank account. 4466 Since protocol **v20** this endpoint is only about 4467 actually confirmed wire transfers. 4468 4469 **Required permission:** ``transfers-read`` 4470 4471 **Request:** 4472 4473 :query payto_uri: *Optional*. Full payto://-URI to filter for transfers to the given bank account (subject and amount MUST NOT be given in the payto:// URI). Note that the URI must be URL-encoded. 4474 4475 :query before: *Optional*. Filter for transfers executed before the given timestamp. 4476 4477 :query after: *Optional*. Filter for transfers executed after the given timestamp. 4478 4479 :query limit: *Optional*. At most return the given number of results. Negative for descending in execution time, positive for ascending in execution time. Default is ``-20``. 4480 4481 :query offset: *Optional*. Starting ``transfer_serial_id`` for an iteration. 4482 4483 :query expected: *Optional*. Filter transfers that we expected to receive (YES: only expected, NO: only unexpected, ALL: default). Since protocol **v20**. 4484 4485 4486 **Response:** 4487 4488 :http:statuscode:`200 OK`: 4489 The body of the response is a `TransferList`. 4490 4491 **Details:** 4492 4493 .. ts:def:: TransferList 4494 4495 interface TransferList { 4496 // List of all the transfers that fit the filter that we know. 4497 transfers : TransferDetails[]; 4498 } 4499 4500 .. ts:def:: TransferDetails 4501 4502 interface TransferDetails { 4503 // How much was wired to the merchant (minus fees). 4504 credit_amount: Amount; 4505 4506 // Raw wire transfer identifier identifying the wire transfer (a base32-encoded value). 4507 wtid: WireTransferIdentifierRawP; 4508 4509 // Full payto://-URI of the bank account that received the wire transfer. 4510 payto_uri: string; 4511 4512 // Base URL of the exchange that made the wire transfer. 4513 exchange_url: string; 4514 4515 // Serial number identifying the transfer in the merchant backend. 4516 // Used for filtering via ``offset``. 4517 transfer_serial_id: Integer; 4518 4519 // Time of the execution of the wire transfer. 4520 execution_time: Timestamp; 4521 4522 // True if we checked the exchange's answer and are happy with it. 4523 // False if we have an answer and are unhappy, missing if we 4524 // do not have an answer from the exchange. 4525 // Removed in protocol **v20**. 4526 verified?: boolean; 4527 4528 // True if the merchant uses the POST /transfers API to confirm 4529 // that this wire transfer took place (and it is thus not 4530 // something merely claimed by the exchange). 4531 // Removed in protocol **v20**. 4532 confirmed?: boolean; 4533 4534 // True if this wire transfer was expected. 4535 // (a matching "/private/incoming" record exists). 4536 // Since protocol **v20**. 4537 expected?: boolean; 4538 } 4539 4540 4541 4542 Querying expected wire transfers 4543 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 4544 4545 .. http:get:: [/instances/$INSTANCE]/private/incoming 4546 4547 Obtain a list of expected incoming wire transfers the backend is 4548 anticipating. 4549 Since protocol **v20**. 4550 4551 **Required permission:** ``transfers-read`` 4552 4553 **Request:** 4554 4555 :query payto_uri: *Optional*. Full payto://-URI to filter for transfers to the given bank account (subject and amount MUST NOT be given in the payto:// URI). Note that the URI must be URL-encoded. 4556 4557 :query before: *Optional*. Filter for transfers executed before the given timestamp. 4558 4559 :query after: *Optional*. Filter for transfers executed after the given timestamp. 4560 4561 :query limit: *Optional*. At most return the given number of results. Negative for descending in execution time, positive for ascending in execution time. Default is ``-20``. 4562 4563 :query offset: *Optional*. Starting ``transfer_serial_id`` for an iteration. 4564 4565 :query verified: *Optional*. Filter transfers by verification status (YES: reconcilation worked, NO: reconciliation failed, ALL: default) 4566 4567 :query confirmed: *Optional*. Filter transfers that were confirmed (YES: credit confirmed, NO: credit still pending, ALL: default) 4568 4569 4570 **Response:** 4571 4572 :http:statuscode:`200 OK`: 4573 The body of the response is a `ExpectedTransferList`. 4574 4575 **Details:** 4576 4577 .. ts:def:: ExpectedTransferList 4578 4579 interface ExpectedTransferList { 4580 // List of all the expected incoming transfers that fit the 4581 // filter that we know. 4582 incoming : ExpectedTransferDetails[]; 4583 } 4584 4585 .. ts:def:: ExpectedTransferDetails 4586 4587 interface ExpectedTransferDetails { 4588 // How much should be wired to the merchant (minus fees). 4589 expected_credit_amount?: Amount; 4590 4591 // Raw wire transfer identifier identifying the wire transfer (a base32-encoded value). 4592 wtid: WireTransferIdentifierRawP; 4593 4594 // Full payto://-URI of the bank account that received the wire transfer. 4595 payto_uri: string; 4596 4597 // Base URL of the exchange that made the wire transfer. 4598 exchange_url: string; 4599 4600 // Serial number identifying the expected transfer in the backend. 4601 // Used for filtering via ``offset``. 4602 expected_transfer_serial_id: Integer; 4603 4604 // Expected time of the execution of the wire transfer 4605 // by the exchange, according to the exchange. 4606 execution_time?: Timestamp; 4607 4608 // True if we checked the exchange's answer and are happy with 4609 // the reconciation data. 4610 // False if we have an answer and are unhappy, missing if we 4611 // do not have an answer from the exchange. 4612 // Does not imply that the wire transfer was settled (for 4613 // that, see ``confirmed``). 4614 validated: boolean; 4615 4616 // True if the merchant uses the POST /transfers API to confirm 4617 // that this wire transfer took place (and it is thus not 4618 // something merely claimed by the exchange). 4619 // (a matching entry exists in /private/transfers) 4620 confirmed: boolean; 4621 4622 // Last HTTP status we received from the exchange, 0 for 4623 // none (incl. timeout) 4624 last_http_status: Integer; 4625 4626 // Last Taler error code we got from the exchange. 4627 last_ec: ErrorCode; 4628 4629 // Last error detail we got back from the exchange. 4630 last_error_detail?: string; 4631 } 4632 4633 4634 Deleting confirmed wire transfer 4635 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 4636 4637 Deleting a wire transfer can be useful in case of a data entry 4638 mistake. In particular, if the exchange base URL was entered 4639 badly, deleting the old entry and adding a correct one is a 4640 good idea. Note that deleting wire transfers is not possible 4641 if they were expected. 4642 4643 .. http:delete:: [/instances/$INSTANCE]/private/transfers/$TID 4644 4645 Here, the TID is the 'transfer_serial_id' of the transfer 4646 to delete. 4647 4648 **Required permission:** ``transfers-write`` 4649 4650 **Response:** 4651 4652 :http:statuscode:`204 No content`: 4653 The transfer was deleted. 4654 :http:statuscode:`404 Not found`: 4655 The transfer was already unknown. 4656 :http:statuscode:`409 Conflict`: 4657 The transfer cannot be deleted anymore. 4658 4659 4660 ----------- 4661 OTP Devices 4662 ----------- 4663 4664 OTP devices can be used to allow offline merchants 4665 to validate that a customer made a payment. 4666 4667 4668 .. http:post:: [/instances/$INSTANCE]/private/otp-devices 4669 4670 This is used to associate an OTP device with an instance. 4671 4672 **Required permission:** ``otp-devices-write`` 4673 4674 **Request:** 4675 4676 The request must be a `OtpDeviceAddDetails`. 4677 4678 **Response:** 4679 4680 :http:statuscode:`204 No content`: 4681 The creation of the template is successful. 4682 :http:statuscode:`404 Not found`: 4683 The merchant instance is unknown or it is not in our data. 4684 4685 **Details:** 4686 4687 .. ts:def:: OtpDeviceAddDetails 4688 4689 interface OtpDeviceAddDetails { 4690 4691 // Device ID to use. 4692 otp_device_id: string; 4693 4694 // Human-readable description for the device. 4695 otp_device_description: string; 4696 4697 // A key encoded with RFC 3548 Base32. 4698 // IMPORTANT: This is not using the typical 4699 // Taler base32-crockford encoding. 4700 // Instead it uses the RFC 3548 encoding to 4701 // be compatible with the TOTP standard. 4702 otp_key: string; 4703 4704 // Algorithm for computing the POS confirmation. 4705 // "NONE" or 0: No algorithm (no pos confirmation will be generated) 4706 // "TOTP_WITHOUT_PRICE" or 1: Without amounts (typical OTP device) 4707 // "TOTP_WITH_PRICE" or 2: With amounts (special-purpose OTP device) 4708 // The "String" variants are supported @since protocol **v7**. 4709 otp_algorithm: Integer | string; 4710 4711 // Counter for counter-based OTP devices. 4712 otp_ctr?: Integer; 4713 } 4714 4715 4716 .. http:patch:: [/instances/$INSTANCE]/private/otp-devices/$DEVICE_ID 4717 4718 This is used to update an OTP device. It is useful when we need to change information in the OTP device or when we have mistake some information. 4719 4720 **Required permission:** ``otp-devices-write`` 4721 4722 **Request:** 4723 4724 The request must be a `OtpDevicePatchDetails`. 4725 4726 **Response:** 4727 4728 :http:statuscode:`204 No content`: 4729 The template has successfully modified. 4730 :http:statuscode:`404 Not found`: 4731 The template(ID) is unknown to the backend. 4732 :http:statuscode:`409 Conflict`: 4733 The provided information is inconsistent with the current state of the template. Changes made is the same with 4734 another store. 4735 4736 **Details:** 4737 4738 .. ts:def:: OtpDevicePatchDetails 4739 4740 interface OtpDevicePatchDetails { 4741 4742 // Human-readable description for the device. 4743 otp_device_description: string; 4744 4745 // A key encoded with RFC 3548 Base32. 4746 // IMPORTANT: This is not using the typical 4747 // Taler base32-crockford encoding. 4748 // Instead it uses the RFC 3548 encoding to 4749 // be compatible with the TOTP standard. 4750 otp_key?: string; 4751 4752 // Algorithm for computing the POS confirmation. 4753 otp_algorithm: Integer; 4754 4755 // Counter for counter-based OTP devices. 4756 otp_ctr?: Integer; 4757 } 4758 4759 4760 .. http:get:: [/instances/$INSTANCE]/private/otp-devices 4761 4762 This is used to return the list of all the OTP devices. 4763 4764 **Required permission:** ``otp-devices-read`` 4765 4766 **Response:** 4767 4768 :http:statuscode:`200 OK`: 4769 The backend has successfully returned all the templates. Returns a `OtpDeviceSummaryResponse`. 4770 :http:statuscode:`404 Not found`: 4771 The backend has does not know about the instance. 4772 4773 **Details:** 4774 4775 .. ts:def:: OtpDeviceSummaryResponse 4776 4777 interface OtpDeviceSummaryResponse { 4778 4779 // Array of devices that are present in our backend. 4780 otp_devices: OtpDeviceEntry[]; 4781 } 4782 4783 .. ts:def:: OtpDeviceEntry 4784 4785 interface OtpDeviceEntry { 4786 4787 // Device identifier. 4788 otp_device_id: string; 4789 4790 // Human-readable description for the device. 4791 device_description: string; 4792 } 4793 4794 .. http:get:: [/instances/$INSTANCE]/private/otp-devices/$DEVICE_ID 4795 4796 This is used to obtain detailed information about a specific OTP device. 4797 4798 The client can provide additional inputs in the query to allow the backend 4799 to compute and return a sample OTP code. Note that it is not an error if 4800 the client provides query arguments that are not being used *or* that are 4801 insufficient for the server to compute the ``otp_code``: If the client 4802 provides inadequate query parameters, the ``otp_code`` is simply omitted 4803 from the response. 4804 4805 **Required permission:** ``otp-devices-read`` 4806 4807 **Query:** 4808 4809 :query faketime=TIMESTAMP: *Optional*. Timestamp in seconds to use when calculating the current OTP code of the device. Since protocol **v10**. 4810 :query price=AMOUNT: *Optional*. Price to use when calculating the current OTP code of the device. Since protocol **v10**. 4811 4812 **Response:** 4813 4814 :http:statuscode:`200 OK`: 4815 The backend has successfully returned the detailed information about a specific OTP device. 4816 Returns a `OtpDeviceDetails`. 4817 :http:statuscode:`404 Not found`: 4818 The OTP device or instance is unknown to the backend. 4819 4820 **Details:** 4821 4822 .. ts:def:: OtpDeviceDetails 4823 4824 interface OtpDeviceDetails { 4825 4826 // Human-readable description for the device. 4827 device_description: string; 4828 4829 // Algorithm for computing the POS confirmation. 4830 // 4831 // Currently, the following numbers are defined: 4832 // 0: None 4833 // 1: TOTP without price 4834 // 2: TOTP with price 4835 otp_algorithm: Integer; 4836 4837 // Counter for counter-based OTP devices. 4838 otp_ctr?: Integer; 4839 4840 // Current time for time-based OTP devices. 4841 // Will match the ``faketime`` argument of the 4842 // query if one was present, otherwise the current 4843 // time at the backend. 4844 // 4845 // Available since protocol **v10**. 4846 otp_timestamp: Integer; 4847 4848 // Current OTP confirmation string of the device. 4849 // Matches exactly the string that would be returned 4850 // as part of a payment confirmation for the given 4851 // amount and time (so may contain multiple OTP codes). 4852 // 4853 // If the ``otp_algorithm`` is time-based, the code is 4854 // returned for the current time, or for the ``faketime`` 4855 // if a TIMESTAMP query argument was provided by the client. 4856 // 4857 // When using OTP with counters, the counter is **NOT** 4858 // increased merely because this endpoint created 4859 // an OTP code (this is a GET request, after all!). 4860 // 4861 // If the ``otp_algorithm`` requires an amount, the 4862 // ``amount`` argument must be specified in the 4863 // query, otherwise the ``otp_code`` is not 4864 // generated. 4865 // 4866 // This field is *optional* in the response, as it is 4867 // only provided if we could compute it based on the 4868 // ``otp_algorithm`` and matching client query arguments. 4869 // 4870 // Available since protocol **v10**. 4871 otp_code?: string; 4872 4873 } 4874 4875 .. http:delete:: [/instances/$INSTANCE]/private/otp-devices/$DEVICE_ID 4876 4877 **Required permission:** ``otp-devices-write`` 4878 4879 **Response:** 4880 4881 :http:statuscode:`204 No content`: 4882 The backend has successfully deleted the OTP device. 4883 :http:statuscode:`404 Not found`: 4884 The backend does not know the instance or the OTP device. 4885 4886 4887 .. _merchant-template-api: 4888 4889 --------- 4890 Templates 4891 --------- 4892 4893 The template is a backend feature that is used to allow wallets to create an 4894 order. This is useful in cases where a store does not have Internet 4895 connectivity or where a Web site wants to enable payments on a purely static 4896 Web page (for example to collect donations). In these cases, the GNU Taler 4897 wallet can be used to setup an order (and then of course pay for it). 4898 4899 The template itself primarily provides order details that cannot be be changed 4900 by the customer when the wallet creates the order. The idea is that the user 4901 *may* be prompted to enter certain information, such as the amount to be paid, 4902 or the order summary (as a reminder to themselves or a message to the store), 4903 while the template provides all of the other contract details. 4904 4905 The typical user-experience with templatates is that the user first scans a QR 4906 code or clicks on a taler://-URI which contains a ``pay-template`` (see `LSD 4907 0006 <https://lsd.gnunet.org/lsd0006/>`__). The URI specifies which values the 4908 user should supply, currently either nothing, the amount, the order summary or 4909 both. The URI may also specify defaults or partial defaults for those 4910 values. After the user has supplied those values, the wallet will use the 4911 public template API to create the order, then fetch the order details, and 4912 proceed as if it had been given the respective ``pay`` URI in the first place: 4913 show the full contract details and allow the user to make a payment. If the 4914 user chooses to aborts the payment, the wallet should give the user the 4915 opportunity to edit the values and create another order with different values. 4916 If the template does not include any values that the user is allowed to edit 4917 (so it is basically a fixed contract), the wallet should directly create the 4918 order and immediately proceed to the contract acceptance dialog. 4919 4920 The business process for the templating API is also pretty simple. First, the 4921 private API is used to setup (or edit) the template, providing all of the 4922 contract terms that subsequently cannot be changed by the customer/wallet. 4923 This template data is then stored under the template ID which can be freely 4924 chosen and must be in URL-encoded format. The SPA should also make it easy 4925 for the merchant to convert the template ID into a taler://-URI and/or QR code. 4926 Here, the merchant must additionally specify the defaults (if any) for the 4927 customer-editable values. Afterwards, the merchant can print out the QR code 4928 for display at the store, add a link to the taler://-URI and/or embed the 4929 respective QR-code image into their Web page. 4930 4931 To receive a payment confirmation, the mechant may choose to configure a 4932 webhook in the merchant backend on the ``pay`` action, for example to send an 4933 SMS to their mobile phone. For points-of-sale without a mobile phone or 4934 Internet connectivity, the OTP mechanism can also be used to confirm payments. 4935 4936 4937 4938 Adding templates 4939 ^^^^^^^^^^^^^^^^ 4940 4941 .. http:post:: [/instances/$INSTANCE]/private/templates 4942 4943 This is used to create a template. 4944 4945 **Required permission:** ``templates-write`` 4946 4947 **Request:** 4948 4949 The request must be a `TemplateAddDetails`. 4950 4951 4952 **Response:** 4953 4954 :http:statuscode:`204 No content`: 4955 The creation of the template is successful. 4956 :http:statuscode:`404 Not found`: 4957 The merchant instance is unknown or it is not in our data. 4958 4959 **Details:** 4960 4961 4962 .. ts:def:: TemplateAddDetails 4963 4964 interface TemplateAddDetails { 4965 4966 // Template ID to use. 4967 template_id: string; 4968 4969 // Human-readable description for the template. 4970 template_description: string; 4971 4972 // OTP device ID. 4973 // This parameter is optional. 4974 otp_id?: string; 4975 4976 // Fixed contract information for orders created from 4977 // this template. 4978 template_contract: TemplateContractDetails; 4979 4980 // Key-value pairs matching a subset of the 4981 // fields from ``template_contract`` that are 4982 // user-editable defaults for this template. 4983 // Since protocol **v13**. 4984 editable_defaults?: Object; 4985 } 4986 4987 4988 .. ts:def:: TemplateContractDetails 4989 4990 interface TemplateContractDetails { 4991 4992 // Human-readable summary for the template. 4993 summary?: string; 4994 4995 // Required currency for payments to the template. 4996 // The user may specify any amount, but it must be 4997 // in this currency. 4998 // This parameter is optional and should not be present 4999 // if "amount" is given. 5000 currency?: string; 5001 5002 // The price is imposed by the merchant and cannot be changed by the customer. 5003 // This parameter is optional. 5004 amount?: Amount; 5005 5006 // Minimum age buyer must have (in years). Default is 0. 5007 minimum_age: Integer; 5008 5009 // The time the customer need to pay before his order will be deleted. 5010 // It is deleted if the customer did not pay and if the duration is over. 5011 pay_duration: RelativeTime; 5012 5013 } 5014 5015 5016 5017 Editing templates 5018 ^^^^^^^^^^^^^^^^^ 5019 5020 5021 .. http:patch:: [/instances/$INSTANCE]/private/templates/$TEMPLATE_ID 5022 5023 This is used to update a template. It is useful when we need to change information in the template or when we have mistake some information. 5024 5025 **Required permission:** ``templates-write`` 5026 5027 **Request:** 5028 5029 The request must be a `TemplatePatchDetails`. 5030 5031 **Response:** 5032 5033 :http:statuscode:`204 No content`: 5034 The template has successfully modified. 5035 :http:statuscode:`404 Not found`: 5036 The template(ID) is unknown to the backend. 5037 :http:statuscode:`409 Conflict`: 5038 The provided information is inconsistent with the current state of the template. Changes made is the same with 5039 another store. 5040 5041 **Details:** 5042 5043 5044 .. ts:def:: TemplatePatchDetails 5045 5046 interface TemplatePatchDetails { 5047 5048 // Human-readable description for the template. 5049 template_description: string; 5050 5051 // OTP device ID. 5052 // This parameter is optional. 5053 otp_id?: string; 5054 5055 // Additional information in a separate template. 5056 template_contract: TemplateContractDetails; 5057 5058 // Key-value pairs matching a subset of the 5059 // fields from ``template_contract`` that are 5060 // user-editable defaults for this template. 5061 // Since protocol **v13**. 5062 editable_defaults?: Object; 5063 } 5064 5065 5066 5067 Inspecting template 5068 ^^^^^^^^^^^^^^^^^^^ 5069 5070 .. http:get:: [/instances/$INSTANCE]/private/templates 5071 5072 This is used to return the list of all the templates. 5073 5074 5075 **Required permission:** ``templates-read`` 5076 5077 **Response:** 5078 5079 :http:statuscode:`200 OK`: 5080 The backend has successfully returned all the templates. Returns a `TemplateSummaryResponse`. 5081 :http:statuscode:`404 Not found`: 5082 The backend has does not know about the instance. 5083 5084 **Details:** 5085 5086 .. ts:def:: TemplateSummaryResponse 5087 5088 interface TemplateSummaryResponse { 5089 5090 // List of templates that are present in our backend. 5091 templates: TemplateEntry[]; 5092 } 5093 5094 The `TemplateEntry` object describes a template. It has the following structure: 5095 5096 .. ts:def:: TemplateEntry 5097 5098 interface TemplateEntry { 5099 5100 // Template identifier, as found in the template. 5101 template_id: string; 5102 5103 // Human-readable description for the template. 5104 template_description: string; 5105 5106 } 5107 5108 .. http:get:: [/instances/$INSTANCE]/private/templates/$TEMPLATE_ID 5109 5110 This is used to obtain detailed information about a specific template. 5111 5112 5113 **Required permission:** ``templates-read`` 5114 5115 **Response:** 5116 5117 :http:statuscode:`200 OK`: 5118 The backend has successfully returned the detailed information about a specific template. 5119 Returns a `TemplateDetails`. 5120 :http:statuscode:`404 Not found`: 5121 The instance or template(ID) is unknown to the backend. 5122 5123 **Details:** 5124 5125 5126 .. ts:def:: TemplateDetails 5127 5128 interface TemplateDetails { 5129 5130 // Human-readable description for the template. 5131 template_description: string; 5132 5133 // OTP device ID. 5134 // This parameter is optional. 5135 otp_id?: string; 5136 5137 // Additional information in a separate template. 5138 template_contract: TemplateContractDetails; 5139 5140 // Key-value pairs matching a subset of the 5141 // fields from ``template_contract`` that are 5142 // user-editable defaults for this template. 5143 // Since protocol **v13**. 5144 editable_defaults?: Object; 5145 5146 // Required currency for payments. Useful if no 5147 // amount is specified in the ``template_contract`` 5148 // but the user should be required to pay in a 5149 // particular currency anyway. Merchant backends 5150 // may reject requests if the ``template_contract`` 5151 // or ``editable_defaults`` do 5152 // specify an amount in a different currency. 5153 // This parameter is optional. 5154 // Since protocol **v13**. 5155 required_currency?: string; 5156 } 5157 5158 5159 5160 Removing template 5161 ^^^^^^^^^^^^^^^^^ 5162 5163 .. http:delete:: [/instances/$INSTANCE]/private/templates/$TEMPLATE_ID 5164 5165 This is used to delete information about a template. If we no longer use it. 5166 5167 **Required permission:** ``templates-write`` 5168 5169 **Response:** 5170 5171 :http:statuscode:`204 No content`: 5172 The backend has successfully deleted the template. 5173 :http:statuscode:`404 Not found`: 5174 The backend does not know the instance or the template. 5175 5176 5177 5178 Using template 5179 ^^^^^^^^^^^^^^ 5180 5181 .. http:get:: [/instances/$INSTANCE]/templates/$TEMPLATE_ID 5182 5183 This is used to obtain information about a specific template by wallets 5184 before they ask the user to fill in details. 5185 This endpoint is available since protocol **v11**. 5186 5187 **Response:** 5188 5189 :http:statuscode:`200 OK`: 5190 The backend has successfully returned the detailed information about a specific template. 5191 Returns a `WalletTemplateDetails`. 5192 :http:statuscode:`404 Not found`: 5193 The instance or template(ID) is unknown to the backend. 5194 5195 **Details:** 5196 5197 .. ts:def:: WalletTemplateDetails 5198 5199 interface WalletTemplateDetails { 5200 5201 // Hard-coded information about the contrac terms 5202 // for this template. 5203 template_contract: TemplateContractDetails; 5204 5205 // Key-value pairs matching a subset of the 5206 // fields from ``template_contract`` that are 5207 // user-editable defaults for this template. 5208 // Since protocol **v13**. 5209 editable_defaults?: Object; 5210 5211 // Required currency for payments. Useful if no 5212 // amount is specified in the ``template_contract`` 5213 // but the user should be required to pay in a 5214 // particular currency anyway. Merchant backends 5215 // may reject requests if the ``template_contract`` 5216 // or ``editable_defaults`` do 5217 // specify an amount in a different currency. 5218 // This parameter is optional. 5219 // Since protocol **v13**. 5220 required_currency?: string; 5221 } 5222 5223 5224 .. http:post:: [/instances/$INSTANCES]/templates/$TEMPLATE_ID 5225 5226 This using template can be modified by everyone and will be used to create order. 5227 5228 5229 **Request:** 5230 5231 The request must be a `UsingTemplateDetails` and we accept JSON application and URL encoded. 5232 5233 5234 **Response:** 5235 5236 The response is exactly the same type of response as when 5237 creating an order using :ref:`POST /private/orders <post-order>`. 5238 5239 **Details:** 5240 5241 .. ts:def:: UsingTemplateDetails 5242 5243 interface UsingTemplateDetails { 5244 5245 // Summary of the template 5246 summary?: string; 5247 5248 // The amount entered by the customer. 5249 amount?: Amount; 5250 } 5251 5252 5253 -------- 5254 Webhooks 5255 -------- 5256 5257 The webhook is a backend feature that is used to send a confirmation to the merchant. It can be send with a SMS, email or with another method. It will confirm that the 5258 customer paid the merchant. It will show the date and the price the customer paid. For details on setup and supported event payloads, see the 5259 `Merchant manual – Setting up a webhook <https://docs.taler.net/taler-merchant-manual.html#setting-up-a-webhook>`_. 5260 5261 Each webhook is bound to an ``event_type``. The backend currently recognizes the following types, which are mirrored in the ``WebhookEventType`` enum so API clients can 5262 validate their payloads without guesswork: 5263 5264 .. ts:def:: WebhookEventType 5265 5266 enum WebhookEventType { 5267 ORDER_CREATED = "order_created", 5268 PAY = "pay", 5269 REFUND = "refund", 5270 ORDER_SETTLED = "order_settled", 5271 CATEGORY_ADDED = "category_added", 5272 CATEGORY_UPDATED = "category_updated", 5273 CATEGORY_DELETED = "category_deleted", 5274 INVENTORY_ADDED = "inventory_added", 5275 INVENTORY_UPDATED = "inventory_updated", 5276 INVENTORY_DELETED = "inventory_deleted" 5277 } 5278 5279 - ``order_created``: fired whenever a new order is created and exposes the ``order_id``, contract, and owning ``instance_id``. 5280 - ``pay``: emitted after a payment succeeds; the payload contains the paid contract terms and ``order_id``. 5281 - ``refund``: triggered when a refund is approved and includes timestamp, refunded amount, and reason. 5282 - ``order_settled``: sent when reconciliation links a wire transfer to an order (includes ``order_id`` and ``wtid``). 5283 - ``category_added`` / ``category_updated`` / ``category_deleted``: cover lifecycle changes to product categories. 5284 - ``inventory_added`` / ``inventory_updated`` / ``inventory_deleted``: cover lifecycle changes to inventory items, including descriptive fields and stock state. 5285 5286 For the full payloads associated with each event consult the merchant manual section linked above. 5287 5288 5289 5290 Adding webhooks 5291 ^^^^^^^^^^^^^^^ 5292 5293 .. http:post:: [/instances/$INSTANCES]/private/webhooks 5294 5295 This is used to create a webhook. 5296 5297 **Required permission:** ``webhooks-write`` 5298 5299 **Request:** 5300 5301 The request must be a `WebhookAddDetails`. 5302 5303 **Response:** 5304 5305 :http:statuscode:`204 No content`: 5306 The creation of the webhook is successsful. 5307 5308 :http:statuscode:`404 Not found`: 5309 The merchant instance is unknown or it not in our data. 5310 5311 **Details:** 5312 5313 .. ts:def:: WebhookAddDetails 5314 5315 interface WebhookAddDetails { 5316 5317 // Webhook ID to use. 5318 webhook_id: string; 5319 5320 // The event of the webhook: why the webhook is used. 5321 event_type: WebhookEventType; 5322 5323 // URL of the webhook where the customer will be redirected. 5324 url: string; 5325 5326 // Method used by the webhook 5327 http_method: string; 5328 5329 // Header template of the webhook 5330 header_template?: string; 5331 5332 // Body template by the webhook 5333 body_template?: string; 5334 5335 } 5336 5337 5338 Editing webhooks 5339 ^^^^^^^^^^^^^^^^ 5340 5341 .. http:patch:: [/instances/$INSTANCES]/private/webhooks/$WEBHOOK_ID 5342 5343 This is used to update a webhook. 5344 5345 **Required permission:** ``webhooks-write`` 5346 5347 **Request:** 5348 5349 The request must be a `WebhookPatchDetails`. 5350 5351 **Response:** 5352 5353 :http:statuscode:`204 No content`: 5354 The webhook has successfully modified. 5355 :http:statuscode:`404 Not found`: 5356 The webhook(ID) is unknown to the backend. 5357 :http:statuscode:`409 Conflict`: 5358 The provided information is inconsistent with the current state of the webhook. Changes made is the same with another store. 5359 5360 **Details:** 5361 5362 .. ts:def:: WebhookPatchDetails 5363 5364 interface WebhookPatchDetails { 5365 5366 // The event of the webhook: why the webhook is used. 5367 event_type: WebhookEventType; 5368 5369 // URL of the webhook where the customer will be redirected. 5370 url: string; 5371 5372 // Method used by the webhook 5373 http_method: string; 5374 5375 // Header template of the webhook 5376 header_template?: string; 5377 5378 // Body template by the webhook 5379 body_template?: string; 5380 5381 } 5382 5383 5384 5385 Inspecting webhook 5386 ^^^^^^^^^^^^^^^^^^ 5387 5388 .. http:get:: [/instances/$INSTANCES]/private/webhooks 5389 5390 This is used to return all the webhooks that are present in our backend. 5391 5392 **Required permission:** ``webhooks-read`` 5393 5394 **Response:** 5395 5396 :http:statuscode:`200 OK`: 5397 The backend has successfully returned all the webhooks. Returns a `WebhookSummaryResponse`. 5398 5399 :http:statuscode:`404 Not found`: 5400 The backend has does not know about the instance. 5401 5402 **Details:** 5403 5404 .. ts:def:: WebhookSummaryResponse 5405 5406 interface WebhookSummaryResponse { 5407 5408 // Return webhooks that are present in our backend. 5409 webhooks: WebhookEntry[]; 5410 5411 } 5412 5413 The `WebhookEntry` object describes a webhook. It has the following structure: 5414 5415 .. ts:def:: WebhookEntry 5416 5417 interface WebhookEntry { 5418 5419 // Webhook identifier, as found in the webhook. 5420 webhook_id: string; 5421 5422 // The event of the webhook: why the webhook is used. 5423 event_type: WebhookEventType; 5424 5425 } 5426 5427 5428 .. http:get:: [/instances/$INSTANCES]/private/webhooks/$WEBHOOK_ID 5429 5430 This is used to obtain detailed information about apecific template. 5431 5432 **Required permission:** ``webhooks-read`` 5433 5434 **Response:** 5435 5436 :http:statuscode:`200 OK`: 5437 The backend has successfully returned the detailed information about a specific webhook. Returns a `WebhookDetails`. 5438 5439 :http:statuscode:`404 Not found`: 5440 The webhook(ID) is unknown to the backend. 5441 5442 **Details:** 5443 5444 .. ts:def:: WebhookDetails 5445 5446 interface WebhookDetails { 5447 5448 // The event of the webhook: why the webhook is used. 5449 event_type: WebhookEventType; 5450 5451 // URL of the webhook where the customer will be redirected. 5452 url: string; 5453 5454 // Method used by the webhook 5455 http_method: string; 5456 5457 // Header template of the webhook 5458 header_template?: string; 5459 5460 // Body template by the webhook 5461 body_template?: string; 5462 5463 } 5464 5465 5466 Removing webhook 5467 ^^^^^^^^^^^^^^^^ 5468 5469 .. http:delete:: [/instances/$INSTANCES]/private/webhooks/$WEBHOOK_ID 5470 5471 This is used to delete information about a webhook. 5472 5473 **Required permission:** ``webhooks-write`` 5474 5475 **Response:** 5476 5477 :http:statuscode:`204 No content`: 5478 The backend has successfully deleted the webhook. 5479 5480 :http:statuscode:`404 Not found`: 5481 The webhook(ID) or the instance is unknown to the backend. 5482 5483 5484 5485 ---------------------------------------- 5486 Token Families: Subscriptions, Discounts 5487 ---------------------------------------- 5488 5489 This API provides functionalities for the issuance, management, and revocation 5490 of token families. Tokens facilitate the implementation of subscriptions and 5491 discounts, engaging solely the merchant and the user. Each token family 5492 encapsulates details pertaining to its respective tokens, guiding the merchant's 5493 backend on the appropriate processing and handling. 5494 5495 5496 Creating token families 5497 ^^^^^^^^^^^^^^^^^^^^^^^ 5498 5499 .. http:post:: [/instances/$INSTANCES]/private/tokenfamilies 5500 5501 This is used to create a token family. 5502 5503 **Required permission:** ``tokenfamilies-write`` 5504 5505 **Request:** 5506 5507 The request must be a `TokenFamilyCreateRequest`. 5508 5509 **Response:** 5510 5511 :http:statuscode:`204 No content`: 5512 The token family was created successfully. 5513 5514 :http:statuscode:`404 Not found`: 5515 The merchant backend is unaware of the instance. 5516 5517 **Details:** 5518 5519 .. ts:def:: TokenFamilyCreateRequest 5520 5521 interface TokenFamilyCreateRequest { 5522 5523 // Identifier for the token family consisting of unreserved characters 5524 // according to RFC 3986. 5525 slug: string; 5526 5527 // Human-readable name for the token family. 5528 name: string; 5529 5530 // Human-readable description for the token family. 5531 description: string; 5532 5533 // Optional map from IETF BCP 47 language tags to localized descriptions. 5534 description_i18n?: { [lang_tag: string]: string }; 5535 5536 // Additional meta data, such as the ``trusted_domains`` 5537 // or ``expected_domains``. Depends on the ``kind``. 5538 extra_data?: object; 5539 5540 // Start time of the token family's validity period. 5541 // If not specified, merchant backend will use the current time. 5542 valid_after?: Timestamp; 5543 5544 // End time of the token family's validity period. 5545 valid_before: Timestamp; 5546 5547 // Validity duration of an issued token. 5548 duration: RelativeTime; 5549 5550 // Rounding granularity for the start validity of keys. 5551 // The desired time is rounded down to a multiple of this 5552 // granularity and then the ``start_offset`` is added to 5553 // compute the actual start time of the token keys' validity. 5554 // The end is then computed by adding the ``duration``. 5555 // Must be 1 minute, 1 hour, 1 day, 1 week, 30 days, 90 days 5556 // or 365 days (1 year). 5557 validity_granularity: RelativeTime; 5558 5559 // Offset to subtract from the start time rounded to ``validity_granularity`` 5560 // to compute the actual start time for a key. 5561 // Default is zero. 5562 start_offset: RelativeTime; 5563 5564 // Kind of the token family. 5565 kind: TokenFamilyKind; 5566 5567 } 5568 5569 .. ts:def:: TokenFamilyKind 5570 5571 enum TokenFamilyKind { 5572 Discount = "discount", 5573 Subscription = "subscription", 5574 } 5575 5576 5577 Updating token families 5578 ^^^^^^^^^^^^^^^^^^^^^^^ 5579 5580 .. http:patch:: [/instances/$INSTANCES]/private/tokenfamilies/$TOKEN_FAMILY_SLUG 5581 5582 This is used to update a token family. 5583 5584 **Required permission:** ``tokenfamilies-write`` 5585 5586 **Request:** 5587 5588 The request must be a `TokenFamilyUpdateRequest`. 5589 5590 **Response:** 5591 5592 :http:statuscode:`204 No Content`: 5593 The token family was successsful updated. 5594 5595 :http:statuscode:`404 Not found`: 5596 The merchant backend is unaware of the token family or instance. 5597 5598 **Details:** 5599 5600 .. ts:def:: TokenFamilyUpdateRequest 5601 5602 interface TokenFamilyUpdateRequest { 5603 5604 // Human-readable name for the token family. 5605 name: string; 5606 5607 // Human-readable description for the token family. 5608 description: string; 5609 5610 // Optional map from IETF BCP 47 language tags to localized descriptions. 5611 description_i18n: { [lang_tag: string]: string }; 5612 5613 // Additional meta data, such as the ``trusted_domains`` 5614 // or ``expected_domains``. Depends on the ``kind``. 5615 extra_data?: object; 5616 5617 // Start time of the token family's validity period. 5618 valid_after: Timestamp; 5619 5620 // End time of the token family's validity period. 5621 valid_before: Timestamp; 5622 5623 } 5624 5625 5626 5627 Inspecting token families 5628 ^^^^^^^^^^^^^^^^^^^^^^^^^ 5629 5630 .. http:get:: [/instances/$INSTANCES]/private/tokenfamilies 5631 5632 This is used to list all configured token families for an instance. 5633 5634 **Required permission:** ``tokenfamilies-read`` 5635 5636 **Response:** 5637 5638 :http:statuscode:`200 OK`: 5639 The merchant backend has successfully returned all token families. 5640 Returns a `TokenFamiliesList`. 5641 5642 :http:statuscode:`404 Not found`: 5643 The merchant backend is unaware of the instance. 5644 5645 **Details:** 5646 5647 .. ts:def:: TokenFamiliesList 5648 5649 // TODO: Add pagination 5650 5651 interface TokenFamiliesList { 5652 5653 // All configured token families of this instance. 5654 token_families: TokenFamilySummary[]; 5655 5656 } 5657 5658 .. ts:def:: TokenFamilySummary 5659 5660 interface TokenFamilySummary { 5661 // Identifier for the token family consisting of unreserved characters 5662 // according to RFC 3986. 5663 slug: string; 5664 5665 // Human-readable name for the token family. 5666 name: string; 5667 5668 // Human-readable description for the token family. 5669 // @since protocol **v23**. 5670 description: string; 5671 5672 // Optional map from IETF BCP 47 language tags to localized descriptions. 5673 // @since protocol **v23**. 5674 description_i18n?: { [lang_tag: string]: string }; 5675 5676 // Start time of the token family's validity period. 5677 valid_after: Timestamp; 5678 5679 // End time of the token family's validity period. 5680 valid_before: Timestamp; 5681 5682 // Kind of the token family. 5683 kind: TokenFamilyKind; 5684 } 5685 5686 5687 .. http:get:: [/instances/$INSTANCES]/private/tokenfamilies/$TOKEN_FAMILY_SLUG 5688 5689 This is used to get detailed information about a specific token family. 5690 5691 **Required permission:** ``tokenfamilies-read`` 5692 5693 **Response:** 5694 5695 :http:statuscode:`200 OK`: 5696 The merchant backend has successfully returned the detailed information 5697 about a specific token family. Returns a `TokenFamilyDetails`. 5698 5699 :http:statuscode:`404 Not found`: 5700 The merchant backend is unaware of the token family or instance. 5701 5702 **Details:** 5703 5704 The `TokenFamilyDetails` object describes a configured token family. 5705 5706 .. ts:def:: TokenFamilyDetails 5707 5708 interface TokenFamilyDetails { 5709 5710 // Identifier for the token family consisting of unreserved characters 5711 // according to RFC 3986. 5712 slug: string; 5713 5714 // Human-readable name for the token family. 5715 name: string; 5716 5717 // Human-readable description for the token family. 5718 description: string; 5719 5720 // Optional map from IETF BCP 47 language tags to localized descriptions. 5721 description_i18n?: { [lang_tag: string]: string }; 5722 5723 // Additional meta data, such as the ``trusted_domains`` 5724 // or ``expected_domains``. Depends on the ``kind``. 5725 extra_data?: object; 5726 5727 // Start time of the token family's validity period. 5728 // No token validities can start before this time 5729 // (but they could be sold before). 5730 valid_after: Timestamp; 5731 5732 // End time of the token family's validity period. 5733 // No tokens will be accepted after this time. 5734 valid_before: Timestamp; 5735 5736 // Validity duration of an issued token. 5737 duration: RelativeTime; 5738 5739 // Rounding granularity for the start validity of keys. 5740 // The desired time is rounded down to a multiple of this 5741 // granularity and then the ``start_offset`` is added to 5742 // compute the actual start time of the token keys' validity. 5743 // The end is then computed by adding the ``duration``. 5744 validity_granularity: RelativeTime; 5745 5746 // Offset in seconds to subtract from the start time rounded to ``validity_granularity`` 5747 // to compute the actual start time for a key. 5748 start_offset: RelativeTime; 5749 5750 // Kind of the token family. 5751 kind: TokenFamilyKind; 5752 5753 // How many tokens have been issued for this family. 5754 issued: Integer; 5755 5756 // How many tokens have been used for this family. 5757 used: Integer; 5758 5759 } 5760 5761 5762 5763 Deleting token families 5764 ^^^^^^^^^^^^^^^^^^^^^^^ 5765 5766 .. http:delete:: [/instances/$INSTANCES]/private/tokenfamilies/$TOKEN_FAMILY_SLUG 5767 5768 This is used to delete a token family. Issued tokens of this family will not 5769 be spendable anymore. 5770 5771 **Required permission:** ``tokenfamilies-write`` 5772 5773 **Response:** 5774 5775 :http:statuscode:`204 No content`: 5776 The backend has successfully deleted the token family. 5777 5778 :http:statuscode:`404 Not found`: 5779 The merchant backend is unaware of the token family or instance. 5780 5781 5782 ----------------------- 5783 Donau Charity Instances 5784 ----------------------- 5785 5786 A merchant instance can link one or more **Donau charity instances**. 5787 Each link associates the instance’s own public key with a charity registered 5788 at some Donau service. These links are managed under the private API. 5789 5790 Permissions 5791 ^^^^^^^^^^^ 5792 5793 * ``donau-read`` — list linked charities. 5794 * ``donau-write`` — add or remove charity links. 5795 5796 Listing charity instances 5797 ^^^^^^^^^^^^^^^^^^^^^^^^^ 5798 5799 .. http:get:: [/instances/$INSTANCE]/private/donau 5800 5801 Return all Donau charity instances currently linked to ``$INSTANCE``. 5802 5803 **Required permission:** ``donau-read`` 5804 5805 **Response:** 5806 5807 :http:statuscode:`200 OK`: 5808 Body is a :ts:type:`DonauInstancesResponse`. 5809 :http:statuscode:`401 Unauthorized`: 5810 Missing or invalid credentials. 5811 :http:statuscode:`404 Not found`: 5812 The merchant instance is unknown. 5813 5814 **Details:** 5815 5816 .. ts:def:: DonauInstancesResponse 5817 5818 interface DonauInstancesResponse { 5819 // List of linked charity instances 5820 donau_instances: DonauInstance[]; 5821 } 5822 5823 .. ts:def:: DonauInstance 5824 5825 interface DonauInstance { 5826 // Serial number identifying the record inside the backend 5827 donau_instance_serial: Integer; 5828 5829 // Base URL of the Donau service 5830 donau_url: string; 5831 5832 // Human-readable charity name 5833 charity_name: string; 5834 5835 // EdDSA public key of the charity (binary) 5836 charity_pub_key: Bytes; 5837 5838 // Charity identifier inside the Donau service 5839 charity_id: Integer; 5840 5841 // Maximum donation amount per calendar year 5842 charity_max_per_year: Amount; 5843 5844 // Cumulative receipts in the current year 5845 charity_receipts_to_date: Amount; 5846 5847 // Calendar year the receipts refer to 5848 current_year: Integer; 5849 5850 // Exchange-style ``/keys`` response published by Donau, 5851 // missing if not yet known to the merchant backend. 5852 donau_keys_json?: object; 5853 } 5854 5855 Adding a charity instance 5856 ^^^^^^^^^^^^^^^^^^^^^^^^^ 5857 5858 .. http:post:: [/instances/$INSTANCE]/private/donau 5859 5860 Link a new Donau charity instance to ``$INSTANCE``. 5861 The backend fetches and validates the charity’s metadata from the given 5862 Donau service before persisting the link. 5863 5864 **Required permission:** ``donau-write`` 5865 5866 **Request:** 5867 5868 The body **must** be a :ts:type:`PostDonauRequest`. 5869 5870 .. ts:def:: PostDonauRequest 5871 5872 interface PostDonauRequest { 5873 // Base URL of the Donau service hosting the charity 5874 donau_url: string; 5875 5876 // Numeric charity identifier inside the Donau service 5877 charity_id: Integer; 5878 } 5879 5880 **Response:** 5881 5882 :http:statuscode:`204 No content`: 5883 The charity link was created successfully. 5884 :http:statuscode:`202 Accepted`: 5885 Operation requires MFA; a :ts:type:`ChallengeResponse` is returned. @since **v21** 5886 :http:statuscode:`400 Bad request`: 5887 Malformed JSON or missing fields. 5888 :http:statuscode:`409 Conflict`: 5889 * The charity is already linked with different parameters, or 5890 * The charity’s public key does **not** match the merchant instance’s public key. 5891 :http:statuscode:`502 Bad gateway`: 5892 Communication with the Donau service failed. 5893 5894 Deleting a charity instance 5895 ^^^^^^^^^^^^^^^^^^^^^^^^^^^ 5896 5897 .. http:delete:: [/instances/$INSTANCE]/private/donau/$DONAU_SERIAL 5898 5899 Unlink the Donau charity instance identified by ``$DONAU_SERIAL``. 5900 5901 **Required permission:** ``donau-write`` 5902 5903 **Response:** 5904 5905 :http:statuscode:`204 No content`: 5906 Charity link removed. 5907 :http:statuscode:`404 Not found`: 5908 No such charity link exists. 5909 5910 5911 5912 ------------------ 5913 The Contract Terms 5914 ------------------ 5915 5916 This section describes the overall structure of 5917 the contract terms that are the foundation for 5918 Taler payments. 5919 5920 .. _contract-terms: 5921 5922 The contract terms must have the following structure: 5923 5924 .. ts:def:: ContractTerms 5925 5926 type ContractTerms = (ContractTermsV1 | ContractTermsV0) & ContractTermsCommon; 5927 5928 .. ts:def:: ContractTermsV1 5929 5930 interface ContractTermsV1 { 5931 // Version 1 supports the ``choices`` array, see 5932 // https://docs.taler.net/design-documents/046-mumimo-contracts.html. 5933 // @since protocol **v21** 5934 version: 1; 5935 5936 // List of contract choices that the customer can select from. 5937 // @since protocol **v21** 5938 choices: ContractChoice[]; 5939 5940 // Map of storing metadata and issue keys of 5941 // token families referenced in this contract. 5942 // @since protocol **v21** 5943 token_families: { [token_family_slug: string]: ContractTokenFamily }; 5944 } 5945 5946 .. ts:def:: ContractTermsV0 5947 5948 interface ContractTermsV0 { 5949 // Defaults to version 0. 5950 version?: 0; 5951 5952 // Total price for the transaction. 5953 // The exchange will subtract deposit fees from that amount 5954 // before transferring it to the merchant. 5955 amount: Amount; 5956 5957 // Maximum total deposit fee accepted by the merchant for this contract. 5958 // Overrides defaults of the merchant instance. 5959 max_fee: Amount; 5960 } 5961 5962 .. ts:def:: ContractTermsCommon 5963 5964 interface ContractTermsCommon { 5965 // Human-readable description of the whole purchase. 5966 summary: string; 5967 5968 // Map from IETF BCP 47 language tags to localized summaries. 5969 summary_i18n?: { [lang_tag: string]: string }; 5970 5971 // Unique, free-form identifier for the proposal. 5972 // Must be unique within a merchant instance. 5973 // For merchants that do not store proposals in their DB 5974 // before the customer paid for them, the ``order_id`` can be used 5975 // by the frontend to restore a proposal from the information 5976 // encoded in it (such as a short product identifier and timestamp). 5977 order_id: string; 5978 5979 // URL where the same contract could be ordered again (if 5980 // available). Returned also at the public order endpoint 5981 // for people other than the actual buyer (hence public, 5982 // in case order IDs are guessable). 5983 public_reorder_url?: string; 5984 5985 // URL that will show that the order was successful after 5986 // it has been paid for. Optional, but either ``fulfillment_url`` 5987 // or ``fulfillment_message`` must be specified in every 5988 // contract terms. 5989 // 5990 // If a non-unique fulfillment URL is used, a customer can only 5991 // buy the order once and will be redirected to a previous purchase 5992 // when trying to buy an order with the same fulfillment URL a second 5993 // time. This is useful for digital goods that a customer only needs 5994 // to buy once but should be able to repeatedly download. 5995 // 5996 // For orders where the customer is expected to be able to make 5997 // repeated purchases (for equivalent goods), the fulfillment URL 5998 // should be made unique for every order. The easiest way to do 5999 // this is to include a unique order ID in the fulfillment URL. 6000 // 6001 // When POSTing to the merchant, the placeholder text "${ORDER_ID}" 6002 // is be replaced with the actual order ID (useful if the 6003 // order ID is generated server-side and needs to be 6004 // in the URL). Note that this placeholder can only be used once. 6005 // Front-ends may use other means to generate a unique fulfillment URL. 6006 fulfillment_url?: string; 6007 6008 // Message shown to the customer after paying for the order. 6009 // Either fulfillment_url or fulfillment_message must be specified. 6010 fulfillment_message?: string; 6011 6012 // Map from IETF BCP 47 language tags to localized fulfillment 6013 // messages. 6014 fulfillment_message_i18n?: { [lang_tag: string]: string }; 6015 6016 // List of products that are part of the purchase (see `Product`). 6017 products: Product[]; 6018 6019 // Time when this contract was generated. 6020 timestamp: Timestamp; 6021 6022 // After this deadline has passed, no refunds will be accepted. 6023 refund_deadline: Timestamp; 6024 6025 // After this deadline, the merchant won't accept payments for the contract. 6026 pay_deadline: Timestamp; 6027 6028 // Transfer deadline for the exchange. Must be in the 6029 // deposit permissions of coins used to pay for this order. 6030 wire_transfer_deadline: Timestamp; 6031 6032 // Merchant's public key used to sign this proposal; this information 6033 // is typically added by the backend. Note that this can be an ephemeral key. 6034 merchant_pub: EddsaPublicKey; 6035 6036 // Base URL of the (public!) merchant backend API. 6037 // Must be an absolute URL that ends with a slash. 6038 merchant_base_url: string; 6039 6040 // More info about the merchant, see below. 6041 merchant: Merchant; 6042 6043 // The hash of the merchant instance's wire details. 6044 h_wire: HashCode; 6045 6046 // Wire transfer method identifier for the wire method associated with ``h_wire``. 6047 // The wallet may only select exchanges via a matching auditor if the 6048 // exchange also supports this wire method. 6049 // The wire transfer fees must be added based on this wire transfer method. 6050 wire_method: string; 6051 6052 // Exchanges that the merchant accepts even if it does not accept any auditors that audit them. 6053 exchanges: Exchange[]; 6054 6055 // Delivery location for (all!) products. 6056 delivery_location?: Location; 6057 6058 // Time indicating when the order should be delivered. 6059 // May be overwritten by individual products. 6060 delivery_date?: Timestamp; 6061 6062 // Nonce generated by the wallet and echoed by the merchant 6063 // in this field when the proposal is generated. 6064 nonce: string; 6065 6066 // Specifies for how long the wallet should try to get an 6067 // automatic refund for the purchase. If this field is 6068 // present, the wallet should wait for a few seconds after 6069 // the purchase and then automatically attempt to obtain 6070 // a refund. The wallet should probe until "delay" 6071 // after the payment was successful (i.e. via long polling 6072 // or via explicit requests with exponential back-off). 6073 // 6074 // In particular, if the wallet is offline 6075 // at that time, it MUST repeat the request until it gets 6076 // one response from the merchant after the delay has expired. 6077 // If the refund is granted, the wallet MUST automatically 6078 // recover the payment. This is used in case a merchant 6079 // knows that it might be unable to satisfy the contract and 6080 // desires for the wallet to attempt to get the refund without any 6081 // customer interaction. Note that it is NOT an error if the 6082 // merchant does not grant a refund. 6083 auto_refund?: RelativeTime; 6084 6085 // Extra data that is only interpreted by the merchant frontend. 6086 // Useful when the merchant needs to store extra information on a 6087 // contract without storing it separately in their database. 6088 // Must really be an Object (not a string, integer, float or array). 6089 extra?: Object; 6090 6091 // Minimum age the buyer must have (in years). Default is 0. 6092 // This value is at least as large as the maximum over all 6093 // mimimum age requirements of the products in this contract. 6094 // It might also be set independent of any product, due to 6095 // legal requirements. 6096 minimum_age?: Integer; 6097 6098 } 6099 6100 .. ts:def:: ContractChoice 6101 6102 interface ContractChoice { 6103 // Price to be paid for this choice. Could be 0. 6104 // The price is in addition to other instruments, 6105 // such as rations and tokens. 6106 // The exchange will subtract deposit fees from that amount 6107 // before transferring it to the merchant. 6108 amount: Amount; 6109 6110 // Human readable description of the semantics of the choice 6111 // within the contract to be shown to the user at payment. 6112 description?: string; 6113 6114 // Map from IETF 47 language tags to localized descriptions. 6115 description_i18n?: { [lang_tag: string]: string }; 6116 6117 // List of inputs the wallet must provision (all of them) to 6118 // satisfy the conditions for the contract. 6119 inputs: ContractInput[]; 6120 6121 // List of outputs the merchant promises to yield (all of them) 6122 // once the contract is paid. 6123 outputs: ContractOutput[]; 6124 6125 // Maximum total deposit fee accepted by the merchant for this contract. 6126 max_fee: Amount; 6127 } 6128 6129 .. ts:def:: ContractInput 6130 6131 // For now, only tokens are supported as inputs. 6132 type ContractInput = ContractInputToken; 6133 6134 .. ts:def:: ContractInputToken 6135 6136 interface ContractInputToken { 6137 type: "token"; 6138 6139 // Slug of the token family in the 6140 // ``token_families`` map on the order. 6141 token_family_slug: string; 6142 6143 // Number of tokens of this type required. 6144 // Defaults to one if the field is not provided. 6145 count?: Integer; 6146 }; 6147 6148 .. ts:def:: ContractOutput 6149 6150 // For now, only tokens are supported as outputs. 6151 type ContractOutput = ContractOutputToken | ContractOutputTaxReceipt; 6152 6153 .. ts:def:: ContractOutputToken 6154 6155 interface ContractOutputToken { 6156 type: "token"; 6157 6158 // Slug of the token family in the 6159 // 'token_families' map on the top-level. 6160 token_family_slug: string; 6161 6162 // Number of tokens to be issued. 6163 // Defaults to one if the field is not provided. 6164 count?: Integer; 6165 6166 // Index of the public key for this output token 6167 // in the `ContractTokenFamily` ``keys`` array. 6168 key_index: Integer; 6169 6170 } 6171 6172 .. ts:def:: ContractOutputTaxReceipt 6173 6174 interface ContractOutputTaxReceipt { 6175 6176 // Tax receipt output. 6177 type: "tax-receipt"; 6178 6179 // Array of base URLs of donation authorities that can be 6180 // used to issue the tax receipts. The client must select one. 6181 donau_urls: string[]; 6182 6183 // Total amount that will be on the tax receipt. 6184 amount: Amount; 6185 6186 } 6187 6188 .. ts:def:: ContractTokenFamily 6189 6190 interface ContractTokenFamily { 6191 // Human-readable name of the token family. 6192 name: string; 6193 6194 // Human-readable description of the semantics of 6195 // this token family (for display). 6196 description: string; 6197 6198 // Map from IETF BCP 47 language tags to localized descriptions. 6199 description_i18n?: { [lang_tag: string]: string }; 6200 6201 // Public keys used to validate tokens issued by this token family. 6202 keys: TokenIssuePublicKey[]; 6203 6204 // Kind-specific information of the token 6205 details: ContractTokenDetails; 6206 6207 // Must a wallet understand this token type to 6208 // process contracts that use or issue it? 6209 critical: boolean; 6210 }; 6211 6212 .. ts:def:: TokenIssuePublicKey 6213 6214 type TokenIssuePublicKey = 6215 | TokenIssueRsaPublicKey 6216 | TokenIssueCsPublicKey; 6217 6218 .. ts:def:: TokenIssueRsaPublicKey 6219 6220 interface TokenIssueRsaPublicKey { 6221 cipher: "RSA"; 6222 6223 // RSA public key. 6224 rsa_pub: RsaPublicKey; 6225 6226 // Start time of this key's signatures validity period. 6227 signature_validity_start: Timestamp; 6228 6229 // End time of this key's signatures validity period. 6230 signature_validity_end: Timestamp; 6231 6232 } 6233 6234 .. ts:def:: TokenIssueCsPublicKey 6235 6236 interface TokenIssueCsPublicKey { 6237 cipher: "CS"; 6238 6239 // CS public key. 6240 cs_pub: Cs25519Point; 6241 6242 // Start time of this key's signatures validity period. 6243 signature_validity_start: Timestamp; 6244 6245 // End time of this key's signatures validity period. 6246 signature_validity_end: Timestamp; 6247 6248 } 6249 6250 .. ts:def:: ContractTokenDetails 6251 6252 type ContractTokenDetails = 6253 | ContractSubscriptionTokenDetails 6254 | ContractDiscountTokenDetails; 6255 6256 .. ts:def:: ContractSubscriptionTokenDetails 6257 6258 interface ContractSubscriptionTokenDetails { 6259 class: "subscription"; 6260 6261 // Array of domain names where this subscription 6262 // can be safely used (e.g. the issuer warrants that 6263 // these sites will re-issue tokens of this type 6264 // if the respective contract says so). May contain 6265 // "*" for any domain or subdomain. 6266 trusted_domains: string[]; 6267 }; 6268 6269 .. ts:def:: ContractDiscountTokenDetails 6270 6271 interface ContractDiscountTokenDetails { 6272 class: "discount"; 6273 6274 // Array of domain names where this discount token 6275 // is intended to be used. May contain "*" for any 6276 // domain or subdomain. Users should be warned about 6277 // sites proposing to consume discount tokens of this 6278 // type that are not in this list that the merchant 6279 // is accepting a coupon from a competitor and thus 6280 // may be attaching different semantics (like get 20% 6281 // discount for my competitors 30% discount token). 6282 expected_domains: string[]; 6283 }; 6284 6285 6286 The wallet must select an exchange that either the merchant accepts directly by 6287 listing it in the exchanges array, or for which the merchant accepts an auditor 6288 that audits that exchange by listing it in the auditors array. 6289 6290 The `Product` object describes the product being purchased from the merchant. 6291 It has the following structure: 6292 6293 .. ts:def:: Product 6294 6295 interface Product { 6296 6297 // Merchant-internal identifier for the product. 6298 product_id?: string; 6299 6300 // Name of the product. 6301 // Since API version **v20**. Optional only for 6302 // backwards-compatibility, should be considered mandatory 6303 // moving forward! 6304 product_name?: string; 6305 6306 // Human-readable product description. 6307 description: string; 6308 6309 // Map from IETF BCP 47 language tags to localized descriptions. 6310 description_i18n?: { [lang_tag: string]: string }; 6311 6312 // Legacy integer portion of the quantity to deliver defaults to 1 if not specified. 6313 quantity?: Integer; 6314 6315 // Preferred quantity string using "<integer>[.<fraction>]" syntax with up to six fractional digits. 6316 unit_quantity?: string; 6317 6318 // Unit in which the product is measured (liters, kilograms, packages, etc.). 6319 unit?: string; 6320 6321 // The price of the product; this is the total price for ``quantity`` times ``unit`` of this product. 6322 price?: Amount; 6323 6324 // An optional base64-encoded product image. 6325 image?: ImageDataUrl; 6326 6327 // A list of taxes paid by the merchant for this product. Can be empty. 6328 taxes?: Tax[]; 6329 6330 // Time indicating when this product should be delivered. 6331 delivery_date?: Timestamp; 6332 } 6333 6334 .. ts:def:: Tax 6335 6336 interface Tax { 6337 // The name of the tax. 6338 name: string; 6339 6340 // Amount paid in tax. 6341 tax: Amount; 6342 } 6343 6344 .. ts:def:: Merchant 6345 6346 interface Merchant { 6347 // The merchant's legal name of business. 6348 name: string; 6349 6350 // Email address for contacting the merchant. 6351 email?: string; 6352 6353 // Label for a location with the business address of the merchant. 6354 website?: string; 6355 6356 // An optional base64-encoded product image. 6357 logo?: ImageDataUrl; 6358 6359 // Label for a location with the business address of the merchant. 6360 address?: Location; 6361 6362 // Label for a location that denotes the jurisdiction for disputes. 6363 // Some of the typical fields for a location (such as a street address) may be absent. 6364 jurisdiction?: Location; 6365 } 6366 6367 6368 .. ts:def:: Location 6369 6370 // Delivery location, loosely modeled as a subset of 6371 // ISO20022's PostalAddress25. 6372 interface Location { 6373 // Nation with its own government. 6374 country?: string; 6375 6376 // Identifies a subdivision of a country such as state, region, county. 6377 country_subdivision?: string; 6378 6379 // Identifies a subdivision within a country sub-division. 6380 district?: string; 6381 6382 // Name of a built-up area, with defined boundaries, and a local government. 6383 town?: string; 6384 6385 // Specific location name within the town. 6386 town_location?: string; 6387 6388 // Identifier consisting of a group of letters and/or numbers that 6389 // is added to a postal address to assist the sorting of mail. 6390 post_code?: string; 6391 6392 // Name of a street or thoroughfare. 6393 street?: string; 6394 6395 // Name of the building or house. 6396 building_name?: string; 6397 6398 // Number that identifies the position of a building on a street. 6399 building_number?: string; 6400 6401 // Free-form address lines, should not exceed 7 elements. 6402 address_lines?: string[]; 6403 } 6404 6405 .. ts:def:: Auditor 6406 6407 interface Auditor { 6408 // Official name. 6409 name: string; 6410 6411 // Auditor's public key. 6412 auditor_pub: EddsaPublicKey; 6413 6414 // Base URL of the auditor. 6415 url: string; 6416 } 6417 6418 .. ts:def:: Exchange 6419 6420 interface Exchange { 6421 // The exchange's base URL. 6422 url: string; 6423 6424 // How much would the merchant like to use this exchange. 6425 // The wallet should use a suitable exchange with high 6426 // priority. The following priority values are used, but 6427 // it should be noted that they are NOT in any way normative. 6428 // 6429 // 0: likely it will not work (recently seen with account 6430 // restriction that would be bad for this merchant) 6431 // 512: merchant does not know, might be down (merchant 6432 // did not yet get /wire response). 6433 // 1024: good choice (recently confirmed working) 6434 priority: Integer; 6435 6436 // Master public key of the exchange. 6437 master_pub: EddsaPublicKey; 6438 6439 // Maximum amount that the merchant could be paid 6440 // using this exchange (due to legal limits). 6441 // New in protocol **v17**. 6442 // Optional, no limit if missing. 6443 max_contribution?: Amount; 6444 } 6445 6446 In addition to the fields described above, 6447 each object (from ``ContractTerms`` down) 6448 can mark certain fields as "forgettable" by listing the names of those fields 6449 in a special peer field ``_forgettable``. 6450 (See :ref:`Private order data cleanup <private-order-data-cleanup>`.)