023-taler-kyc.rst (73962B)
1 DD 23: Taler KYC 2 ################ 3 4 :Design status: Accepted 5 :Implementation status: Implemented 6 :DD shepherd: TBD 7 :Historical contributors: Florian Dold, Christian Grothoff, Özgür Kesim 8 :First published: 2021-09-12 9 :Last substantive change: 2026-05-03 10 :Implementation evidence: exchange (2024-04-22) 11 :Normative references: :doc:`../core/api-exchange`, :doc:`../taler-kyc-manual` 12 13 .. note:: 14 15 This is a living design rationale. The core exchange API and KYC manual 16 are authoritative for implemented endpoints and operations. 17 18 Summary 19 ======= 20 21 This document discusses the Know-your-customer (KYC) and Anti-Money Laundering 22 (AML) processes supported by Taler. 23 24 25 Motivation 26 ========== 27 28 To legally operate, Taler has to comply with KYC/AML regulation that requires 29 banks to identify parties involved in transactions at certain points. 30 31 32 Requirements 33 ============ 34 35 Taler needs to take *measures* based on the following primary *triggers*: 36 37 * Customer withdraws money over a monthly threshold 38 39 * exchange triggers KYC 40 * key: IBAN (encoded as payto:// URI) 41 42 * Wallet receives (via refunds) money resulting in a balance over a threshold 43 44 * this is a client-side restriction 45 * key: reserve (=KYC account) long term public key per wallet (encoded as payto:// URI) 46 47 * Wallet receives money via P2P payments 48 49 * there are two sub-cases: PUSH and PULL payments 50 * key: reserve (=KYC account) long term public key per wallet (encoded as payto:// URI) 51 52 * Merchant receives money (Q: any money, or above a monthly threshold?) 53 54 * key: IBAN (encoded as payto:// URI) 55 56 * Reserve is "opened" for invoicing. 57 58 * key: reserve (=KYC account) long term public key per wallet (encoded as payto:// URI) 59 60 * Import of new sanctions lists and triggering of measures against matches of existing 61 customer records against the list 62 63 For the different operation types, there can be both soft and hard 64 limits. Soft limits are those that the customer may raise by providing data 65 and passing KYC checks. Hard limits cannot be lifted, for example because an 66 exchange forbids crossing those limits in its terms of service for all 67 customers. 68 69 70 Process requirements 71 ^^^^^^^^^^^^^^^^^^^^ 72 73 The key consideration here is *plausibilization*: staff needs to 74 check that the client-provided information is plausible. As this 75 is highly case-dependent, this cannot be automated. 76 77 For the different *measures*, there are various different possible KYC/AML 78 *checks* that could happen: 79 80 * In-person validation by AML staff 81 * Various forms to be filled by AML staff 82 * Validation involving local authorities and post-office 83 * Online validation, sometimes with multiple options (like KYC for multiple people): 84 85 * Forms to be supplied by user (different types of ID) 86 * Interactive video 87 * Documents to be supplied (business register) 88 * Address validation (e-mail or phone or postal) 89 90 Additionally, the process is dynamic and conditional upon various decisions: 91 92 * Individual vs. business 93 * PEP or non-PEP 94 * Hit on sanctions list 95 * Type of business (trust, foundation, listed on stock market, etc.) 96 * Need for plausibilization (via documents by user or staff research) 97 * Periodic updates (of customer data, of sanction lists) and re-assessment 98 99 There are also various *outcomes*: 100 101 * normal operation (with expiration date) 102 * normal operation but with AML staff investigating (new measure) 103 * held, requesting customer documentation (new measure) 104 * held, AML staff reviewing evidence for plausibilization (new measure) 105 * automatically frozen until certain day (due to sanctions) 106 * institutionally frozen until certain day (due to order by state authority) 107 * operation is categorically not allowed (at least above certain limits) 108 109 Outcomes may also be (partially) public, that is exposed to the client. For 110 example, we may want to tell a wallet that it has hit a hard withdraw limit, 111 but might succeed at withdrawing a smaller amount. 112 113 The outcome of a *check* can set new rules or trigger another *measure* (the 114 latter is conditional on reaching the expiration time of the outcome). 115 116 As a result, we largely end up in a large state machine where the AML staff has 117 serious flexibility while the user needs guidance as to the possible next moves 118 and/or to the current state of their account (where some information must not be 119 disclosed). 120 121 122 Documentation requirements 123 ^^^^^^^^^^^^^^^^^^^^^^^^^^ 124 125 For each account we must: 126 127 * define risk-profile (902.4, 905.1) 128 * document the specific setup, likely not just the INI file 129 * should have some key Anti-Money-Laundering Act (AMLA) 130 file attributes, such as: 131 132 * File opened, file closed (keep data for X years afterwards!) 133 * low-risk or high-risk business relationship 134 * PEP status 135 * business domain 136 * authority notification dates (possibly multiple) with 137 voluntary or mandatory notification classification 138 139 Finally, we need to produce statistics: 140 141 * There must be a page with an overview of AMLA files with opening 142 and closing dates and an easy way to determine for any day the 143 number of open AMLA files 144 * Technically, we also need a list of at-risk transactions and of 145 frozen transactions, but given that we can really only freeze 146 on an account-basis, I think there is nothing to do here 147 * number of incidents reported (voluntarily, required) 148 * number of business relationships at any point in time 149 * number of risky business relationships (PEP, etc.) 150 * number of frozen transactions (authority vs. sanction) with start-date and end-date 151 * start-data and end-date of relationships (data retained for X years after end of relationship) 152 153 For this high-level monitoring, we need certain designated critical events to 154 be tracked in the system statistics: 155 156 * account opened 157 * set to high risk 158 * set to low risk 159 * suspicious activity report filed with authority 160 * account frozen 161 * account unfrozen 162 * account closed 163 * sanction list import / update 164 165 166 Sanction lists 167 ^^^^^^^^^^^^^^ 168 169 .. note:: 170 171 The implementation described in the current KYC manual supersedes this 172 historical design sketch. 173 174 We need to be able to import new sanction lists (whenever they are published) 175 and then check existing AMLA files against those lists. Additionally, newly 176 created AMLA files must be checked against the current list and some "measure" 177 applied in case of a match. 178 179 This will primarily require us to define an endpoint to upload a sanction list 180 and to define a new table to track the list of sanctioned entities. As it is 181 expected that sanction lists will not permit fully automated determinations in 182 all cases, an external "sanction check" program should be configured which 183 compares records against the current list and determines the correct measure, 184 such as no change, further manual review by AML staff, or even automatic 185 freeze (and report) depending on how well the records match. 186 187 Basically, the "sanction check" program takes the sanction list and an 188 attribute set to compute the same kind of `AmlOutcome` that an AML program 189 outputs given a context and an attribute set. 190 191 192 Security requirements 193 ^^^^^^^^^^^^^^^^^^^^^ 194 195 IBANs are predictable. We (probably) do not want random people to be able to 196 initate KYC processes for other parties. Similarly, the attestation API 197 requires us to somehow *authenticate* the user to ensure we only give out 198 attestation data to the data subject themselves. For P2P payments and 199 withdrawals, we have the reserve public key that is only known to the data 200 subject and thus can be used to authenticate the client via a signature. Only 201 pure deposits (by merchants or directly from a wallet) are a problem as the 202 only thing we know about the receiver is the IBAN at that time, and literally 203 any user could just deposit money into some bank account, so knowledge of the 204 IBAN is insufficient to determine that we actually are communicating with the 205 owner of the bank account. 206 207 208 Further considerations 209 ^^^^^^^^^^^^^^^^^^^^^^ 210 211 On top of all of this, we need to plan some *diagnostics* to determine when 212 components fail (such as scripts or external services providing malformed 213 results). 214 215 Optionally, in the future, the solution should support fees to be paid by the 216 user for *voluntary* KYC processes related to attestation (#7365). 217 218 219 Proposed Solution 220 ================= 221 222 The main state of an account is represented by a set of `KYC rules <KycRule>` (the 223 `LegitimizationRuleSet`) which specify the current *rules* to apply to 224 transactions involving the account. Rules can *exposed* to the account owner, 225 or can be secret. Each *rule* specifies certain *conditions* which, if met, 226 *trigger* a set of *measures*. After a *rule* was *triggered* and 227 before the *outcome* of a respective *measure* has been produced (say 228 because the user did not yet enter their data or the AML officer is still 229 reviewing the case), the existing rules remain in force. Rules have a display 230 priority, and if a second rule with a higher display priority is also 231 triggered, the *measures* of the higher-priority rule become the active 232 *measures*. Except for the default rule set, every legitimization rule set 233 also has an *expiration* time after which a successor *measure* (or the 234 default rule set) is automatically triggered. 235 236 For any possible *measures*, we define: 237 238 * Contextual input data to be provided (with dynamic inputs, 239 e.g. amount set dynamically based on the *trigger* could be 240 in the context) 241 * A *check* to be performed (checks can be user-interactive (LINK, FORM) 242 or staff-interactive (INFO)) 243 * A fallback *measure* to take on failure of a user-interactive check 244 (if the check fails, we cannot run the AML *program* as required inputs 245 might be missing!) 246 * An (AML) *program* that uses *attribtes* from the *check* as well as 247 *context* data to determine an *outcome* represented as the 248 `AmlOutcome`. 249 250 "verboten" is the name of a special *measure*, which means that crossing the 251 respective transaction threshold is categorically not allowed (for this 252 account). "verboten" with a threshold of zero can be used to freeze funds. 253 254 Possible *outcomes* of a measure include: 255 256 * The next operational state (normal, AML investigation) of the account 257 (basically, whether to add it to the work list of AML staff). 258 * A new set of *rules* in the form of a `LegitimizationRuleSet` that 259 determines custom rules to apply to transactions involving the account; 260 such rules may be used to block certain transactions by using the 261 "verboten" measure. The `LegitimizationRuleSet` also must specify 262 an *expiration* time by which we fall back to a successor measure 263 *or* to the default rules. 264 * A (largely) free-form set of `AccountProperties` that AML staff can 265 use to tag accounts with. Some default properties are defined, but 266 the exchange does not do anything with these and AML SPAs are free to 267 use any properties they like. Account properties are only exposed 268 to AML staff and never to the customer. 269 * A set of *events* that are to be added to the timeline of the 270 operator for statistical purposes. 271 272 For the user-interactive *checks* we need a KYC SPA that is given: 273 274 * instructions to render (with either a form to fill or links to external checks); 275 here the context could provide an array of choices! 276 * possibly an external check that was set up (if any); for cost-reasons, we 277 should only do one at a time, and probably should then always redirect the 278 browser to that check. 279 280 For the staff-interactive *checks* we need an AML SPA: 281 282 * to file forms and upload documentation (without state transition) 283 * to decide on next measure (providing context); here, the exchange needs 284 to expose the list of available *measures* and required *context* for each 285 286 We need some customer-driven interactivity in KYB/KYC process, for example the 287 user may need to be given choices (address vs. phone, individual vs. business, 288 order in which to provide KYC data of beneficiaries). As a result, the 289 exchange needs to serve some SPA for *measures* where the user is shown the 290 next step(s) or choices (which person to collect KYC data on, whether to run 291 challenger on phone number of physical address, etc.). The SPA should also 292 potentially contain a form to allow the customer to directly upload documents 293 to us (like business registration) instead of to some KYC provider. This is 294 because KYC providers may not be flexible enough. The SPA should also allow 295 the customer to perform KYC checks voluntarily. 296 297 Similarly, the AML staff will need to be able to trigger rather complex 298 KYB/KYC processes, like "need KYC on X and Y and Z" or "phone number or 299 mailing address" or "please upload form A/T/S". Here in particular it 300 should be possible to request not only filled forms, but arbitrary 301 documents. 302 303 304 Terminology 305 ^^^^^^^^^^^ 306 307 * **Attributes**: Attributes are used to represent KYC data obtained about 308 an account holder. Attributes include passport images, address data, 309 business registration documents, and indeed arbitrary forms filed by 310 AML staff or the customer themselves. Attribute data is considered 311 sensitive private information and is thus stored encrypted within the 312 exchange database. 313 314 * **Check**: A check establishes a particular attribute of a user, such as 315 their name based on an ID document and lifeness, mailing address, phone 316 number, taxpayer identity, etc. Checks may be given *context* (such as 317 whether a customer is an individual or a business) to run correctly. Checks 318 can also be AML staff inserting information for plausibilization. Checks 319 result in *attributes* about the account's owner which are given to an 320 external AML *program* together with the *context* to determine an *outcome*. 321 KYC checks are always specified with a fallback *measure* to be taken if 322 the check fails. 323 324 * **Condition**: A condition specifies when KYC is required. Conditions 325 include the *type of operation*, a threshold amount (e.g. above EUR:1000) 326 and possibly a time period (e.g. over the last month). 327 328 * **Configuration**: The configuration determines the *legitimization rules*, 329 and specifies which providers offer which *checks*. 330 331 * **Context**: Context is information provided as input into a *check* and 332 *program* to customize their execution. The context is initially set by the 333 *measure* (possibly including data from the *trigger*). Naturally, the 334 *program* may use its `AmlProgramInput` which includes *context* and 335 *attribute* data to compute an update *context* for the next set of 336 *measures* that it specifies in the `LegitimizationRuleSet` as part 337 of the `AmlOutcome`. Thus, *context* is something that typically 338 evolves as the *account* undergoes *measures*. Context is lost if 339 an account transitions to default *legitimization rules* due to 340 *expiration*. 341 342 * **Display priority**: Every rule has a *display priority*. If a second 343 *rule* is *triggered* before the *outcome* of a *rule* could be determined, 344 the *rule* with the larger *display priority* becomes the requirement that 345 the account owner has to satisfy (and that thus will be displayed by the 346 KYC SPA). 347 348 * **Expiration**: Except for the default rules, any set of KYC rules is 349 subject to *expiration*. This can be because *attributes* become outdated or 350 because sanctions have a time limit. The expiration time thus determines 351 when a new *measure* is triggered in the absence of a transaction crossing 352 thresholds in the current set of *legtimization rules*. 353 354 * **Legitimization rules**: The *legitimization rules* determine under which 355 *conditions* which *measures* will be taken. A `LegitimizationRuleSet` 356 always also includes an *expiration* time period for (custom, non-default) 357 *legitimization rules* after which a fallback measure* will automatically 358 apply. Legitimization rules may be *exposed* to the client (for example, 359 to allow a wallet to stay below hard withdraw thresholds) or could be secret. 360 361 * **Logic**: Logic refers to a specific bit of code (realized as an exchange 362 plugin) that enables the interaction with a specific *provider*. Logic 363 typically requires *configuration* for access control (such as an 364 authorization token) and possibly the endpoint of the specific *provider* 365 implementing the respective API. 366 367 * **Measure**: Describes the possible outgoing edges from one state in the 368 state machine (including how to show the current state). Each edge is given 369 some *context* and a *check* to be performed as well as an AML *program* 370 which determines the *outcome*. We generally distinguish between 371 "original" measures (defined globally in the exchange configuration) and 372 "custom" measures (defined specifically for an account by AML staff). 373 374 * **Outcome**: An `AmlOutcome` describes the account state that an account 375 ends up in due to either an AML staff action or an AML *program* doing some 376 computation over the attributes resulting from a *check*. Outcomes can be 377 that certain types of transactions are "verboten", that the account is (or 378 remains) under investigation by AML staff, that the account is given certain 379 properties, and/or that certain events are to be logged. Outcomes also 380 include a new set of *legitimization rules* to apply (and an *expiration* 381 time at which point a successor *measure* will be automatically taken). 382 383 * **Provider**: A provider performs a specific set of *checks* at a certain 384 *cost*. Interaction with a provider is performed by provider-specific 385 *logic*. 386 387 * **Program**: An AML helper *program* is given *context* about the current 388 state of an account and the attribute data from a *check* to compute the 389 *outcome*. For example, a *program* may look at the "PEP" field of a KYC 390 check and decide if the outcome is to put the account into ``normal`` or 391 ``held-for-manual-review`` state. AML programs are always specified 392 with a fallback *measure* to be taken if the program fails. 393 394 * **Trigger**: A specific transaction that satisfies a **Condition**. 395 396 * **Type of operation**: The operation type determines which Taler-specific 397 operation has triggered the KYC requirement. We support four types of 398 operation: withdraw (by customer), deposit (by merchant), P2P receive (by 399 wallet) and (high) wallet balance. 400 401 402 Account owner authentication 403 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 404 405 Access to the KYC SPA (or rather, its account-specific state) is controlled by 406 a *target token* (which is effectively like a bearer token, except passed 407 inside the URL). The *target token* ensures that only the account owner has 408 access to the KYC processes. It can be obtained by authenticating using 409 either the merchant private key or reserve private key, depending on the type 410 of the account (IBAN or wallet-reserve respectively). 411 412 When we need to authenticate a bank account owner, we will simply require them 413 to make an outgoing wire transfer into the exchange bank account with a public 414 key in the wire transfer subject (just like when withdrawing), but augmented 415 with the string "KYC" so we can distinguish the wire transfer from a regular 416 withdrawal. Typically, we would put the merchant public key into the wire 417 transfer subject; wallets MAY put their long-term reserve public key instead. 418 The amount to be transferred is the *KYC fee*. 419 420 This has several advantages: 421 422 * Only the account owner can provide us with the public key, so we already 423 have also one super-hard piece of KYC evidence. 424 * If the account owner looses their public key, it's not a problem: they 425 would just have to do the transfer again with a new key. No need for 426 us to do any kind of intervention for key management. 427 * We could theoretically get paid to do the KYC process, or just "charge" a 428 nominal amount. 429 * This also somewhat addresses the payment for voluntary KYC processes where 430 a merchant wants to do KYC to get us to attest their identity for their 431 customers even if we do not yet have a legal need. The only issue here 432 is that this does not work if voluntary KYC is invoiced while mandatory 433 KYC is gratis. But, that kind of configuration is a business decision 434 and there is no hard need to support it immediately. 435 * This definitively addresses the need for authentication to access the 436 attestation API, which so far was only available for P2P payments as 437 we could not authenticate merchants. 438 * The "KYC" string allows us to distinguish the authentication transfers from 439 withdrawal transfers; by keeping the KYC fee at or below the closing fee, 440 we can even deploy this without fully updating the logic everywhere to 441 distinguish KYC transfers 442 443 444 451 Response 445 ^^^^^^^^^^^^ 446 447 When KYC operations are required, various endpoints may respond with a 448 ``451 Unavailable for Legal Reasons`` status code and a `LegitimizationNeededResponse` 449 body. 450 451 New endpoints 452 ^^^^^^^^^^^^^ 453 454 .. http:get:: /kyc-check/$H_PAYTO 455 456 Checks the KYC status of a particular payment target and possibly begins a 457 KYC process by allowing the customer to choose the next KYC measure to 458 satisfy. This endpoint is typically used by wallets or merchants that 459 have been told that a transaction is not happening because it triggered 460 some KYC/AML measure and now want to check how the KYC/AML 461 requirement could be fulfilled (or whether it already has been 462 satisfied and the operation can now proceed). Long-polling may be used 463 to instantly observe a change in the KYC requirement status. 464 465 The payto hash of the ``/kyc-check/`` endpoint encodes the 466 account (or wallet) for which legitimization measures are determined. 467 It is returned in `LegitimizationNeededResponse` responses as in 468 the case of withdraw, the wallet may not know the debited bank account. 469 470 Given a valid pair of payto hash and account owner signature, the 471 ``/kyc-check/`` endpoint returns either just the KYC status or redirects the 472 client (202) to the next required stage of the KYC process. The redirection 473 must be for an HTTP(S) endpoint to be triggered via a simple HTTP GET. It 474 must always be the same endpoint for the same client, as the wallet/merchant 475 backend are not required to check for changes to this endpoint. Clients 476 that received a 202 status code may repeat the request and use long-polling 477 to detect a change of the HTTP status. 478 479 **Request:** 480 481 *Account-Owner-Signature*: 482 483 The client must provide Base-32 encoded EdDSA signature with 484 ``$ACCOUNT_PRIV``, affirming the desire to obtain KYC data. Note that 485 this is merely a simple authentication mechanism, the details of the 486 request are not protected by the signature. The ``$ACCOUNT_PRIV`` is 487 either the (wallet long-term) reserve private key or the merchant instance 488 private key. 489 490 :query timeout_ms=NUMBER: *Optional.* If specified, the exchange will 491 wait up to ``timeout_ms`` milliseconds if the requirement continues 492 to be mandatory provisioning of KYC data by the client. 493 Ignored if the HTTP status code is already ``200 Ok``. Note that 494 clients cannot long-poll for AML staff actions, so status information 495 about an account being under AML review needs to be requested 496 periodically. 497 498 **Response:** 499 500 :http:statuscode:`200 Ok`: 501 No mandatory KYC actions are required by the client at this time. 502 The client *may* still visit the KYC URL to initiate voluntary checks. 503 The response will be an `AccountKycStatus` object which specifies 504 restrictions that currently apply to the account. If the 505 client attempts to exceed *soft* limits, the status may change 506 to a ``202 Accepted``. Hard limits cannot be lifted by passing KYC checks. 507 :http:statuscode:`202 Accepted`: 508 The account holder performed an operation that would have crossed 509 *soft* limits and must be redirected to the provided location to perform 510 the required KYC checks to satisfy the legal requirements. Afterwards, the 511 ``/kyc-check/`` request should be repeated to check whether the 512 user has completed the process. 513 The response will be an `AccountKycStatus` object. 514 :http:statuscode:`204 No content`: 515 The exchange is not configured to perform KYC and thus 516 the legal requirements are already satisfied. 517 :http:statuscode:`403 Forbidden`: 518 The provided signature is not acceptable for the payto hash. 519 :http:statuscode:`404 Not found`: 520 The requirement row is unknown. 521 522 .. http:get:: /aml-spa/$FILENAME 523 524 Serves the resources of the AML SPA. 525 526 .. http:get:: /kyc-spa/$FILENAME 527 528 Serves the resources of the KYC SPA. Note that 529 ``$FILENAME`` must be syntactically distinct from 530 the access token. Any ``$ACCESS_TOKEN`` will be 531 mapped internally to "index.html". 532 533 .. http:get:: /kyc-spa/$ACCESS_TOKEN 534 535 A set of ``/kyc-spa/$ACCESS_TOKEN`` GET endpoints is created per account 536 hash that serves the KYC SPA. This is where the ``/kyc-check/`` endpoint 537 will in principle redirect clients. The KYC SPA will use the 538 ``$ACCESS_TOKEN`` of its URL to initialize itself via the 539 ``/kyc-info/$ACCESS_TOKEN`` endpoint family. The KYC SPA may download 540 additional resources via ``/kyc-spa/$FILENAME``. The filenames must not 541 match base32-encoded 256-bit values. 542 543 .. http:get:: /kyc-info/$ACCESS_TOKEN 544 545 The ``/kyc-info/$ACCESS_TOKEN`` endpoints are created per client 546 account hash (but access controlled via a unique target token) 547 to return information about the state of the KYC or AML process 548 to the KYC SPA. The SPA uses this information to show the user an 549 appropriate dialog. The SPA should also long-poll this endpoint for changes 550 to the AML/KYC state. Note that this is a client-facing endpoint, so it will 551 only provide a restricted amount of information to the customer (as some 552 laws may forbid us to inform particular customers about their true status). 553 The endpoint will typically inform the SPA about possible choices to 554 proceed, such as directly uploading files, contacting AML staff, or 555 proceeding with a particular KYC process at an external provider (such as 556 Challenger). If the user chooses to initate a KYC process at an external 557 provider, the SPA must request the respective process to be set-up by the 558 exchange via the ``/kyc-start/`` endpoint. 559 560 **Request:** 561 562 *If-None-Match*: 563 The client MAY provide an ``If-None-Match`` header with an ETag. 564 565 :query timeout_ms=MILLISECONDS: 566 *Optional.* If specified, the exchange will wait up to MILLISECONDS for 567 a change to a more recent legitimization measure before returning a 304 568 Not Modified status. 569 570 **Response:** 571 572 *Etag*: Will be set to the serial ID of the measure. Used for long-polling (only for 200 OK responses). 573 574 :http:statuscode:`200 OK`: 575 The body is a `KycProcessClientInformation`. 576 :http:statuscode:`204 No Content`: 577 There are no open KYC requirements or possible voluntary checks 578 the client might perform. 579 :http:statuscode:`304 Not Modified`: 580 The KYC requirements did not change. 581 582 583 .. http:post:: /kyc-upload/$ID 584 585 The ``/kyc-upload/$ID`` POST endpoint allows the SPA to upload 586 client-provided evidence. The ``$ID`` will be provided as part of the 587 ``/kyc-info`` body. This is for checks of type ``FORM``. In practice, 588 ``$ID`` will encode both the ``$ACCESS_TOKEN`` and the index of the selected 589 measure (but this should be irrelevant for the client). 590 591 **Request:** 592 593 Basically oriented along the possible formats of a HTTP form being 594 POSTed. Details will depend on the form. The server will try to decode the 595 uploaded body from whatever format it is provided in. 596 597 **Response:** 598 599 :http:statuscode:`204 No Content`: 600 The information was successfully uploaded. The SPA should fetch 601 an updated ``/kyc-info/``. 602 :http:statuscode:`404 Not Found`: 603 The ``$ID`` is unknown to the exchange. 604 :http:statuscode:`409 Conflict`: 605 The upload conflicts with a previous upload. 606 :http:statuscode:`413 Request Entity Too Large`: 607 The body is too large. 608 609 .. http:post:: /kyc-start/$ID 610 611 The ``/kyc-start/$ID`` POST endpoint allows the SPA to set up a new external 612 KYC process. It will return the URL that the client must GET to begin the 613 KYC process. The SPA should probably open this URL in a new window or tab. 614 The ``$ID`` will be provided as part of the ``/kyc-info`` body. In 615 practice, ``$ID`` will encode both the ``$ACCESS_TOKEN`` and the index of 616 the selected measure (but this should be irrelevant for the client). 617 618 **Request:** 619 620 Use empty JSON body for now. 621 622 **Response:** 623 624 :http:statuscode:`200 Ok`: 625 The KYC process was successfully initiated. The URL is in a 626 `KycProcessStartInformation` object. 627 628 :http:statuscode:`404 Not Found`: 629 The ``$ID`` is unknown to the exchange. 630 631 .. note:: 632 633 As this endpoint is involved in every KYC check at the beginning, this 634 is also the place where we could integrate the payment process for the KYC fee 635 in the future (since **vATTEST**). 636 637 638 .. http:get:: /kyc-proof/$PROVIDER_SECTION?state=$H_PAYTO 639 640 Upon completion of the process at the external KYC provider, the provider 641 must redirect the client (browser) to trigger a GET request to a new 642 ``/kyc-proof/$H_PAYTO/$PROVIDER_SECTION`` endpoint. Once this endpoint is 643 triggered, the exchange will pass the received arguments to the respective 644 logic plugin. The logic plugin will then (asynchronously) update the KYC 645 status of the user. The logic plugin should redirect the user to the KYC 646 SPA. This endpoint deliberately does not use the ``$ACCESS_TOKEN`` as the 647 external KYC provider should not learn that token. 648 649 This endpoint is thus accessed from the user's browser at the *end* of a KYC 650 process, possibly providing the exchange with additional credentials to 651 obtain the results of the KYC process. Specifically, the URL arguments 652 should provide information to the exchange that allows it to verify that the 653 user has completed the KYC process. The details depend on the logic, which 654 is selected by the "$PROVIDER_SECTION". 655 656 While this is a GET (and thus safe, and idempotent), the operation may 657 actually trigger significant changes in the exchange's state. In 658 particular, it may update the KYC status of a particular payment target. 659 660 **Request:** 661 662 Details on the request depend on the specific KYC logic that was used. 663 664 If the KYC plugin logic is OAuth 2.0, the query parameters are: 665 666 :query code=CODE: 667 OAuth 2.0 code argument. 668 :query state=STATE: 669 OAuth 2.0 state argument with the H_PAYTO. 670 671 .. note:: 672 673 Depending on the OAuth variant used, additional 674 query parameters may need to be passed here. 675 676 **Response:** 677 678 Given that the response is returned to a user using a browser and **not** to 679 a Taler wallet, the response format is in human-readable HTML and not in 680 machine-readable JSON. 681 682 :http:statuscode:`302 Found`: 683 The KYC operation succeeded and the 684 payment target is now authorized to transact. 685 The browser is redirected to a human-readable 686 page configured by the exchange operator. 687 :http:statuscode:`401 Unauthorized`: 688 The provided authorization token is invalid. 689 :http:statuscode:`404 Not found`: 690 The payment target is unknown. 691 :http:statuscode:`502 Bad Gateway`: 692 The exchange received an invalid reply from the 693 legitimization service. 694 :http:statuscode:`504 Gateway Timeout`: 695 The exchange did not receive a reply from the legitimization 696 service within a reasonable time period. 697 698 699 .. http:get:: /kyc-webhook/$PROVIDER_SECTION/* 700 .. http:post:: /kyc-webhook/$PROVIDER_SECTION/* 701 .. http:get:: /kyc-webhook/$LOGIC/* 702 .. http:post:: /kyc-webhook/$LOGIC/* 703 704 Alternatively, the KYC confirmation may be triggered by a ``/kyc-webhook`` 705 request. As KYC **providers** do not necessarily support passing detailed 706 information in the URL arguments, the ``/kyc-webhook`` only needs to specify 707 either the ``PROVIDER_SECTION`` *or* the ``LOGIC`` (the name of the plugin 708 implementing the KYC API). The API-specific webhook logic must then figure 709 out what exactly the webhook is about on its own. The ``/kyc-webhook/`` 710 endpoint works for GET or POST, again as details depend on the KYC provider. 711 In contrast to ``kyc-proof``, the response does NOT go to the end-users' 712 browser and should thus only indicate success or failure. 713 714 **Request:** 715 716 Details on the request depend on the specific KYC logic that was used. 717 718 **Response:** 719 720 :http:statuscode:`204 No content`: 721 The operation succeeded. 722 :http:statuscode:`404 Not found`: 723 The specified logic is unknown. 724 725 726 .. http:post:: /kyc-wallet 727 728 The ``/kyc-wallet`` POST endpoint allows a wallet to notify an exchange if 729 it will cross a balance threshold. Here, the ``balance`` specified should be 730 the threshold (from the ``wallet_balance_limit_without_kyc`` array) that the 731 wallet would cross, and *not* the *exact* balance of the wallet. The exchange 732 will respond with a wire target UUID. The wallet can then use this UUID to 733 begin the KYC process at ``/kyc-check/``. The wallet must only proceed to 734 obtain funds exceeding the threshold after the KYC process has concluded. 735 While wallets could be "hacked" to bypass this measure (we cannot 736 cryptographically enforce this), such modifications are a terms of service 737 violation which may have legal consequences for the user. 738 739 Setup KYC identification for a wallet. Returns the KYC UUID. This endpoint 740 is used by compliant Taler wallets when they are about to hit the balance 741 threshold and thus need to have the customer provide their personal details 742 to the exchange. The wallet is identified by its long-lived reserve public 743 key (which is used for P2P payments, not for withdrawals). 744 745 **Request:** 746 747 The request body must be a `WalletKycRequest` object. 748 749 **Response:** 750 751 :http:statuscode:`204 No Content`: 752 KYC is disabled at this exchange, or the balance is below the 753 threshold that requires KYC, or this wallet already satisfied 754 the KYC check for the given balance. 755 :http:statuscode:`403 Forbidden`: 756 The provided signature is invalid. 757 This response comes with a standard `ErrorDetail` response. 758 :http:statuscode:`451 Unavailable for Legal Reasons`: 759 The wallet must undergo a KYC check. A KYC ID was created. 760 The response will be a `LegitimizationNeededResponse` object. 761 762 .. http:get:: /aml/$OFFICER_PUB/measures 763 764 To enable the AML staff SPA to give AML staff a choice of possible measures, a 765 new endpoint ``/aml/$OFFICER_PUB/measures`` is added that allows the AML SPA 766 to dynamically GET the list of available measures. It returns a list of known 767 KYC checks (by name) with their descriptions and a list of AML programs with 768 information about the required context. 769 770 **Request:** 771 772 *Taler-AML-Officer-Signature*: 773 The client must provide Base-32 encoded EdDSA signature with 774 ``$OFFICER_PRIV``, affirming the desire to obtain AML data. Note that 775 this is merely a simple authentication mechanism, the details of the 776 request are not protected by the signature. 777 778 **Response:** 779 780 :http:statuscode:`200 Ok`: 781 Information about possible measures is returned in a 782 `AvailableMeasureSummary` object. 783 784 .. http:get:: /aml/$OFFICER_PUB/kyc-statistics/$NAME 785 786 Returns the number of KYC events matching the given event type ``$NAME`` in 787 the specified time range. Note that this query can be slow as the 788 statistics are computed on-demand. (This is OK as such requests should be 789 rare.) 790 791 **Request:** 792 793 *Taler-AML-Officer-Signature*: 794 The client must provide Base-32 encoded EdDSA signature with 795 ``$OFFICER_PRIV``, affirming the desire to obtain AML data. Note that this 796 is merely a simple authentication mechanism, the details of the request are 797 not protected by the signature. 798 799 :query start_date=TIMESTAMP: 800 *Optional*. Specifies the date when to 801 start looking (inclusive). If not given, the start time of the 802 exchange operation is used. 803 :query end_date=TIMESTAMP: 804 *Optional*. Specifies the date when to 805 stop looking (exclusive). If not given, the current date is used. 806 807 **Response:** 808 809 :http:statuscode:`200 OK`: 810 The response will be an `EventCounter` message. 811 812 .. http:get:: /aml/$OFFICER_PUB/decisions 813 814 **Request:** 815 816 *Taler-AML-Officer-Signature*: 817 The client must provide Base-32 encoded EdDSA signature with 818 ``$OFFICER_PRIV``, affirming the desire to obtain AML data. Note that 819 this is merely a simple authentication mechanism, the details of the 820 request are not protected by the signature. 821 822 :query limit: 823 *Optional*. takes value of the form ``N (-N)``, so that at 824 most ``N`` values strictly older (younger) than ``start`` are returned. 825 Defaults to ``-20`` to return the last 20 entries (before ``start``). 826 :query offset: 827 *Optional*. Row number threshold, see ``delta`` for its 828 interpretation. Defaults to ``INT64_MAX``, namely the biggest row id 829 possible in the database. 830 :query h_payto: 831 *Optional*. Account selector. All matching accounts are returned if this 832 filter is absent, otherwise only decisions for this account. 833 :query active: 834 *Optional*. If set to yes, only return active decisions, if no only 835 decisions that have been superseded. Do not give (or use "all") to 836 see all decisions regardless of activity status. 837 :query investigation: 838 *Optional*. If set to yes, only return accounts that are under 839 AML investigation, if no only accounts that are not under investigation. 840 Do not give (or use "all") to see all accounts regardless of 841 investigation status. 842 843 **Response:** 844 845 :http:statuscode:`200 OK`: 846 The response will be an `AmlDecisionsResponse` message. 847 :http:statuscode:`204 No content`: 848 There are no matching AML records. 849 :http:statuscode:`403 Forbidden`: 850 The signature is invalid. 851 :http:statuscode:`404 Not found`: 852 The designated AML account is not known. 853 :http:statuscode:`409 Conflict`: 854 The designated AML account is not enabled. 855 856 .. http:get:: /aml/$OFFICER_PUB/attributes/$H_PAYTO 857 858 Obtain attributes obtained as part of AML/KYC processes for a 859 given account. 860 861 **Request:** 862 863 *Taler-AML-Officer-Signature*: 864 The client must provide Base-32 encoded EdDSA signature with 865 ``$OFFICER_PRIV``, affirming the desire to obtain AML data. Note that 866 this is merely a simple authentication mechanism, the details of the 867 request are not protected by the signature. 868 869 :query limit: 870 *Optional*. takes value of the form ``N (-N)``, so that at 871 most ``N`` values strictly older (younger) than ``start`` are returned. 872 Defaults to ``-20`` to return the last 20 entries (before ``start``). 873 :query offset: 874 *Optional*. Row number threshold, see ``delta`` for its 875 interpretation. Defaults to ``INT64_MAX``, namely the biggest row id 876 possible in the database. 877 878 **Response:** 879 880 :http:statuscode:`200 OK`: 881 The response will be an `KycAttributesResponse` message. 882 :http:statuscode:`204 No content`: 883 There are no matching KYC attributes. 884 :http:statuscode:`403 Forbidden`: 885 The signature is invalid. 886 :http:statuscode:`404 Not found`: 887 The designated AML account is not known. 888 :http:statuscode:`409 Conflict`: 889 The designated AML account is not enabled. 890 891 .. http:post:: /aml/$OFFICER_PUB/decision 892 893 Make an AML decision. Triggers the respective action and 894 records the justification. 895 896 **Request:** 897 898 The request body must be an `AmlDecisionRequest` message. 899 900 **Response:** 901 902 :http:statuscode:`204 No Content`: 903 The AML decision has been executed and recorded successfully. 904 :http:statuscode:`403 Forbidden`: 905 The signature is invalid. 906 :http:statuscode:`404 Not Found`: 907 The address the decision was made upon is unknown to the exchange or 908 the designated AML account is not known. 909 :http:statuscode:`409 Conflict`: 910 The designated AML account is not enabled or a more recent 911 decision was already submitted. 912 913 Modifications to existing endpoints 914 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 915 916 .. note:: 917 918 This subsection describes an earlier KYC API design. The core exchange API 919 and KYC manual supersede its endpoint names and processing model. 920 921 When withdrawing, the exchange checks if the KYC status is acceptable. If no 922 KYC was done and if either the amount withdrawn over a particular timeframe 923 exceeds the threshold or the reserve received a P2P transfer, then a 924 ``451 Unavailable for Legal Reasons`` is returned which redirects the consumer 925 to the new ``/kyc-check/`` handler. 926 927 When depositing, the exchange aggregator (!) checks the KYC status and if 928 negative, returns an additional information field via the 929 ``aggregation_transient`` table which is returned via GET ``/deposits/`` to the 930 merchant. 931 932 When merging into a reserve, the KYC status is checked and again the 933 merge fails with ``451 Unavailable for Legal Reasons`` to trigger the 934 KYC process. 935 936 To allow the wallet to do the KYC check if it is about to exceed a set balance 937 threshold, we modify the ``/keys`` response to add an optional array 938 ``wallet_balance_limit_without_kyc`` of threshold amounts is returned. 939 Whenever the wallet crosses one of these thresholds for the first time, it 940 should trigger the KYC process. If this field is absent, there is no limit. 941 If the field is provided, a correct wallet must create a long-term 942 account-reserve key pair. This should be the same key that is also used to 943 receive wallet-to-wallet payments. Then, *before* a wallet performs an 944 operation that would cause it to exceed the balance threshold in terms of 945 funds held from a particular exchange, it *should* first request the user to 946 complete the KYC process. For that, the wallet should POST to the new 947 ``/kyc-wallet`` endpoint, providing its long-term reserve-account public key 948 and a signature requesting permission to exceed the account limit. 949 950 951 Configuration of external KYC providers 952 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 953 954 For each KYC provider that could contribute to checks the configuration 955 specifies a ``$PROVIDER_SECTION`` for each authentication procedure. For each 956 (enabled) provider, the exchange has a logic plugin which (asynchronously) 957 determines the redirect URL for a given wire target. See below for a 958 description of the high-level process for different providers. 959 960 .. code-block:: ini 961 962 [kyc-provider-$PROVIDER_ID] 963 964 # Which plugin is responsible for this provider? 965 LOGIC = PLUGIN_NAME 966 967 # Plus additional logic-specific options, e.g.: 968 AUTHORIZATION_TOKEN = superdupersecret 969 970 # Other logic-specific internal options (example): 971 FORM_ID = business_legi_form 972 973 974 Configuration of possible KYC/AML checks 975 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 976 977 The configuration specifies a set of possible KYC checks offered by external 978 providers, one per configuration section: 979 980 .. code-block:: ini 981 982 [kyc-check-$CHECK_NAME] 983 984 # Which type of check is this? Also determines 985 # the SPA form to show to the user for this check. 986 # 987 # INFO: wait for staff or contact staff out-of band 988 # (only information shown, no SPA action) 989 # FORM: SPA should show an inline (HTML) form 990 # LINK: SPA may start external KYC process or upload 991 # 992 TYPE = INFO|LINK|FORM 993 994 # Provider id, present only if type is LINK. 995 # Refers to a ``kyc-provider-$PROVIDER_ID`` section. 996 PROVIDER_ID = id 997 998 # Name of the SPA form, if type is FORM 999 # "INFO" and "LINK" are reserved and must not be used. 1000 # The exchange server and the SPA must agree on a list 1001 # of supported forms and the resulting attributes. 1002 # 1003 # The SPA should include a JSON resource file 1004 # "forms.json" mapping form names to arrays of 1005 # attribute names each form provides. 1006 FORM_NAME = name 1007 1008 # Descriptions to use in the SPA to display the check. 1009 DESCRIPTION = "Upload your passport picture" 1010 DESCRIPTION_I18N = "{"en":"Upload scan of your passport"}" 1011 1012 # ';'-separated list of fields that the CONTEXT must 1013 # provide as inputs to this check. For example, 1014 # for a FORM of type CHOICE, this might state 1015 # ``choices: string[];``. The type after the ":" 1016 # is for now purely for documentation and is 1017 # not checked. However, it may be shown to AML staff 1018 # when they configure measures. 1019 REQUIRES = requirement; 1020 1021 # Description of the outputs provided by the check. 1022 # Basically, the check's output is expected to 1023 # provide the following fields as attribute inputs into 1024 # a subsequent AML program. 1025 # Only given for type FORM; INFO never has any outputs, 1026 # and for type LINK we can obtain the same information 1027 # from the CONVERTER via ``--list-outputs``. 1028 OUTPUTS = business_name street city country registration 1029 1030 # **original** measure to take if the check fails 1031 # (for any reason, e.g. provider or form fail to 1032 # satisfy constraints or provider signals user error) 1033 # Usually should point to a measure that requests 1034 # AML staff to investigate. The fallback measure 1035 # context always includes the reasons for the 1036 # failure. 1037 FALLBACK = MEASURE_NAME 1038 1039 The list of possible FORM names is fixed in the SPA 1040 for a particular exchange release. 1041 1042 The outcome of *any* check should always be uploaded encrypted into the 1043 ``kyc_attributes`` table. It MUST include an ``expiration_time``. 1044 1045 The "check_name" value "skip" is reserved and must not be defined. It can be 1046 used in measures where the AML program must be run immediately without any 1047 input. 1048 1049 1050 Configuration of legitimization requirement triggers 1051 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 1052 1053 The configuration also specifies a set of legitimization rules including the 1054 condition and the measure the condition triggers, one condition per 1055 configuration section: 1056 1057 .. code-block:: ini 1058 1059 [kyc-rule-$RULE_NAME] 1060 1061 # Operation that triggers this rule. 1062 # Must be one of "WITHDRAW", "DEPOSIT", 1063 # (p2p) "MERGE", (wallet) "BALANCE", 1064 # (reserve) "CLOSE", "AGGREGATE", 1065 # "TRANSACTION" or "REFUND". 1066 OPERATION_TYPE = WITHDRAW 1067 1068 # Space-separated list of next measures to be performed. 1069 # The SPA should display *all* of these measures to the user. 1070 # (They have a choice of either which ones, or in 1071 # which order they are to be performed.) 1072 # A special measure name "verboten" is used if the 1073 # specified threshold may never be crossed 1074 # (under this set of rules). 1075 NEXT_MEASURES = SWISSNESS KYB 1076 1077 # "YES" if all NEXT_MEASURES will eventually need 1078 # to be satisfied, "NO" if the user has a choice between 1079 # them. Not actually enforced by the exchange, but 1080 # primarily used to inform the user whether this is 1081 # an "and" or "or". YES for "and". 1082 IS_AND_COMBINATOR = YES 1083 1084 # YES if the rule (specifically, operation type, 1085 # threshold, timeframe) and the general nature of 1086 # the next measure (verboten or approval required) 1087 # should be exposed to the client. 1088 # Defaults to NO if not set. 1089 EXPOSED = YES 1090 1091 # Threshold amount above which the rule is 1092 # triggered. The total must be exceeded in the given 1093 # timeframe. 1094 THRESHOLD = KUDOS:100 1095 1096 # Timeframe over which the amount to be compared to 1097 # the THRESHOLD is calculated. 1098 # Ignored for WALLET-BALANCE. Can be 'forever'. 1099 TIMEFRAME = 30 days 1100 1101 # Set to YES to enable the rule (default is NO) 1102 ENABLED = NO 1103 1104 1105 AML programs 1106 ^^^^^^^^^^^^ 1107 1108 AML programs are helper programs that can: 1109 1110 * Generate a list of *required* context field names 1111 for the helper (introspection!) using the "--required-context" 1112 command-line switch. The output should use the same 1113 syntax as the REQUIRES clause of ``[kyc-check-]`` 1114 configuration sections, except that new lines 1115 MUST be used to separate fields instead of ";". 1116 * Generate a list of *required* attribute names 1117 for the helper (introspection!) using the "--required-attributes" 1118 command-line switch. The output should use the same 1119 list of names as the ATTRIBUTES in the 1120 ``[kyc-provider-]`` configuration section 1121 (but may also include FORM field names). 1122 * Process an input JSON object of type 1123 `AmlProgramInput` into a JSON object of 1124 type `AmlOutcome`. 1125 This is the default behavior if no command-line switches 1126 are provided. 1127 1128 If the AML program fails (exits with a failure code or 1129 does not provide well-formed JSON output) the AML/KYC 1130 process continues with the FALLBACK measure. This should 1131 usually be one that asks AML staff to contact the 1132 systems administrator. 1133 1134 AML programs are listed in the configuration file, one program per section: 1135 1136 .. code-block:: ini 1137 1138 [aml-program-$PROG_NAME] 1139 1140 # Program to run. 1141 COMMAND = taler-helper-aml-pep 1142 1143 # Human-readable description of what this 1144 # AML helper program will do. Used to show 1145 # to the AML staff. 1146 DESCRIPTION = "check if the customer is a PEP" 1147 1148 # True if this AML program is enabled (and thus can be 1149 # used in measures and exposed to AML staff). 1150 # Optional, default is NO. 1151 ENABLED = YES 1152 1153 # **original** measure to take if COMMAND fails 1154 # Usually points to a measure that asks AML staff 1155 # to contact the systems administrator. The fallback measure 1156 # context always includes the reasons for the 1157 # failure. 1158 FALLBACK = MEASURE_NAME 1159 1160 1161 Configuration of measures 1162 ^^^^^^^^^^^^^^^^^^^^^^^^^ 1163 1164 Finally, the configuration specifies a set of 1165 **original** *measures* one per configuration section: 1166 1167 .. code-block:: ini 1168 1169 [kyc-measure-$MEASURE_NAME] 1170 1171 # Possible check for this measure. Optional. 1172 # If not given, PROGRAM should be run immediately 1173 # (on an empty set of attributes). 1174 CHECK_NAME = IB_FORM 1175 1176 # Context for the check. The context can be 1177 # just an empty JSON object if there is none. 1178 CONTEXT = {"choices":["individual","business"]} 1179 1180 # Program name to run on the context and check data to 1181 # determine the outcome and next measure. 1182 # Refers to a ``[aml-program-$PROG_NAME]`` section name. 1183 PROGRAM = taler-aml-program 1184 1185 # Optional. Set to YES to allow this measure to be 1186 # done voluntarily by a client. Used to offer the 1187 # KYC SPA to display measure even if they are 1188 # not required. Default is NO. 1189 VOLUNTARY = YES/NO 1190 1191 1192 If ``CHECK_NAME`` is set to "SKIP" (or is not provided at all), the AML 1193 ``PROGRAM`` is to be run immediately. This is useful if no client-interaction 1194 is required to arrive at a decision. 1195 1196 .. note:: 1197 1198 The list of *measures* is not complete: AML staff may freely define new 1199 measures dynamically, usually by selecting checks, an AML program, and 1200 providing context. 1201 1202 1203 Sanity checking 1204 ^^^^^^^^^^^^^^^ 1205 1206 On start-up, ``taler-exchange-httpd`` should sanity-check its 1207 configuration. Specifically, it should validate that for all AML programs the 1208 input requirements (attributes and context) are claimed to be satisfied by the 1209 respective checks that may trigger those programs, and similarly that for all 1210 checks the original measures satisfy the context requirements for their KYC 1211 checks. 1212 1213 As a result, any component (AML program, form or external check) is warranted 1214 to be always called with the declared required inputs. Furthermore, we can 1215 detect if a component fails to produce the required output and the 1216 configuration contains (presumably safe) FALLBACKs to address this case. The 1217 exchange *MUST* detect circular failures, like when a FALLBACK triggers a 1218 measure that itself immediately triggers again the same FALLBACK. 1219 1220 1221 Exchange database schema 1222 ^^^^^^^^^^^^^^^^^^^^^^^^ 1223 1224 We introduce a new ``wire_targets`` table into the exchange database. This 1225 table is referenced as the source or destination of payments (regular deposits 1226 and also P2P payments). A positive side-effect is that we reduce duplication 1227 in the ``reserves_in``, ``wire_out`` and ``deposits`` tables as they can 1228 reference this table. 1229 1230 We introduce a new ``legitimization_processes`` table that tracks the status 1231 of a legitimization process at a provider, including the configuration section 1232 name, the user/account name at the provider, and some legitimization 1233 identifier for the process at the provider. In this table, we additionally 1234 store information related to the KYC status of the underlying payto://-URI, in 1235 particular when the KYC expires (0 if it was never done). 1236 1237 Finally, we introduce a new ``legitimization_requirements`` table that 1238 contains a list of checks required for a particular wire target. When KYC is 1239 triggered (say when some endpoint returns an HTTP status code of 451) a 1240 new requirement is first put into the requirements table. Then, when the 1241 client identifies as business or individual the specific legitimization 1242 process is started. When the taler-exchange-aggregator triggers a KYC check 1243 the merchant can observe this when a 202 (Accepted) status code is returned 1244 on GET ``/deposits/`` with the respective legitimization requirement row. 1245 1246 1247 .. sourcecode:: sql 1248 1249 CREATE TABLE wire_targets 1250 (wire_target_serial_id BIGSERIAL UNIQUE 1251 ,wire_target_h_payto BYTEA PRIMARY KEY CHECK (LENGTH(wire_target_h_payto)=32), 1252 ,access_token BYTEA UNIQUE CHECK (LENGTH(access_token)=32) DEFAULT gen_random_bytes(32) 1253 ,target_pub BYTEA CHECK (LENGTH(target_pub)=32) DEFAULT NULL 1254 ,payto_uri STRING NOT NULL 1255 ) 1256 PARTITION BY HASH (wire_target_h_payto); 1257 1258 COMMENT ON TABLE wire_targets 1259 IS 'All recipients of money via the exchange'; 1260 COMMENT ON COLUMN wire_targets.h_payto 1261 IS 'Unsalted hash of payto_uri'; 1262 COMMENT ON COLUMN wire_targets.access_token 1263 IS 'high-entropy random value that is used as a token to authorize access to the KYC process (without requiring a signature by target_priv)'; 1264 COMMENT ON COLUMN wire_targets.target_pub 1265 IS 'Public key (reserve_pub or merchant_pub) associated with the account; NULL if KYC is not allowed for the account (if there was no incoming KYC wire transfer yet); updated, thus NOT available to the auditor'; 1266 COMMENT ON COLUMN wire_targets.payto_uri 1267 IS 'Can be a regular bank account, or also be a URI identifying a reserve-account (for P2P payments)'; 1268 1269 CREATE TABLE IF NOT EXISTS legitimization_measures 1270 (legitimization_measure_serial_id INT8 GENERATED BY DEFAULT AS IDENTITY 1271 ,access_token BYTEA NOT NULL UNIQUE CHECK (LENGTH(access_token)=32) 1272 REFERENCES wire_targets (access_token) 1273 ,start_time INT8 NOT NULL 1274 ,jmeasures TEXT NOT NULL 1275 ,display_priority INT4 NOT NULL 1276 ,is_finished BOOL NOT NULL DEFAULT(FALSE) 1277 ) 1278 PARTITION BY HASH (access_token); 1279 1280 COMMENT ON TABLE legitimization_measures 1281 IS 'Rules that have been triggered for the account (FIXME: check this is consistent with usage)'; 1282 COMMENT ON COLUMN legitimization_measures.access_token 1283 IS 'Used to uniquely identify the account and as a symmetric access control mechanism for the SPA'; 1284 COMMENT ON COLUMN legitimization_measures.start_time 1285 IS 'Time when the measure was triggered (by decision or rule)'; 1286 COMMENT ON COLUMN legitimization_measures.jmeasures 1287 IS 'JSON object of type LegitimizationMeasures with KYC/AML measures for the account encoded'; 1288 COMMENT ON COLUMN legitimization_measures.display_priority 1289 IS 'Display priority of the rule that triggered this measure; if in the meantime another rule also triggers, the measure is only replaced if the new rule has a higher display priority'; 1290 COMMENT ON COLUMN legitimization_measures.is_finished 1291 IS 'Set to TRUE if this set of measures was processed; used to avoid indexing measures that are done'; 1292 1293 CREATE INDEX ON legitimization_measures (access_token) 1294 WHERE NOT is_finished; 1295 1296 CREATE TABLE legitimization_outcomes 1297 (outcome_serial_id INT8 GENERATED BY DEFAULT AS IDENTITY 1298 ,h_payto BYTEA CHECK (LENGTH(h_payto)=32) 1299 REFERENCES wire_targets (wire_target_h_payto) 1300 ,decision_time INT8 NOT NULL DEFAULT(0) 1301 ,expiration_time INT8 NOT NULL DEFAULT(0) 1302 ,jproperties TEXT, 1303 ,new_measure_name TEXT, 1304 ,to_investigate BOOL NOT NULL 1305 ,is_active BOOL NOT NULL DEFAULT(TRUE) 1306 ,jnew_rules TEXT NOT NULL 1307 ) 1308 PARTITION BY HASH (h_payto); 1309 1310 COMMENT ON TABLE legitimization_outcomes 1311 IS 'Outcomes can come from AML programs'; 1312 COMMENT ON COLUMN legitimization_outcomes.h_payto 1313 IS 'hash of the payto://-URI this outcome is about'; 1314 COMMENT ON COLUMN legitimization_outcomes.decision_time 1315 IS 'when was this outcome decided'; 1316 COMMENT ON COLUMN legitimization_outcomes.expiration_time 1317 IS 'time when the decision expires and the expiration jnew_rules should be applied'; 1318 COMMENT ON COLUMN legitimization_outcomes.jproperties 1319 IS 'JSON object of type AccountProperties, such as PEP status, business domain, risk assessment, etc.'; 1320 COMMENT ON COLUMN legitimization_outcomes.to_investigate 1321 IS 'AML staff should investigate the activity of this account'; 1322 COMMENT ON COLUMN legitimization_outcomes.is_active 1323 IS 'TRUE if this is the current authoritative legitimization outcome'; 1324 COMMENT ON COLUMN legitimization_outcomes.new_measure_name 1325 IS 'space-separated list of measures to trigger immediately, NULL for none, prefixed with a "+" to indicate AND combination for the measures'; 1326 COMMENT ON COLUMN legitimization_outcomes.jnew_rules 1327 IS 'JSON object of type LegitimizationRuleSet with rules to apply to the various operation types for this account; all KYC checks should first check if active new rules for a given account exist in this table (and apply specified measures); if not, it should check the default rules to decide if a measure is required'; 1328 1329 CREATE INDEX legitimization_outcomes_active 1330 ON legitimization_outcomes(h_payto) 1331 WHERE is_active; 1332 1333 CREATE TABLE legitimization_processes 1334 (legitimization_process_serial_id BIGSERIAL UNIQUE 1335 ,h_payto BYTEA NOT NULL CHECK (LENGTH(h_payto)=64) 1336 REFERENCES wire_targets (wire_target_h_payto) 1337 ,start_time INT8 NOT NULL 1338 ,expiration_time INT8 NOT NULL DEFAULT (0) 1339 ,legitimization_measure_serial_id INT8 1340 REFERENCES legitimization_measures (legitimization_measure_serial_id) 1341 ,measure_index INT4 1342 ,provider_section TEXT NOT NULL 1343 ,provider_user_id TEXT DEFAULT NULL 1344 ,provider_legitimization_id TEXT DEFAULT NULL 1345 ,redirect_url TEXT DEFAULT NULL 1346 ,finished BOOLEAN DEFAULT (FALSE) 1347 ) 1348 PARTITION BY HASH (h_payto); 1349 1350 COMMENT ON TABLE legitimization_processes 1351 IS 'here we track KYC processes we initiated with external providers; the main reason is so that we do not initiate a second process when an equivalent one is still active; note that h_payto, provider_section, jcontext must match and the process must not be finished or expired for an existing redirect_url to be re-used; given that clients may voluntarily initiate KYC processes, there may not always be a legitimization_measure that triggered the setup'; 1352 COMMENT ON COLUMN legitimization_processes.h_payto 1353 IS 'foreign key linking the entry to the wire_targets table, NOT a primary key (multiple KYC setups are possible per wire target)'; 1354 COMMENT ON COLUMN legitimization_processes.start_time 1355 IS 'when was the legitimization process initiated'; 1356 COMMENT ON COLUMN legitimization_processes.expiration_time 1357 IS 'when does the process expire (and needs to be manually set up again)'; 1358 COMMENT ON COLUMN legitimization_processes.measure_index 1359 IS 'index of the measure in legitimization_measures that was selected for this KYC setup; NULL if legitimization_measure_serial_id is NULL; enables determination of the context data provided to the external process'; 1360 COMMENT ON COLUMN legitimization_processes.provider_section 1361 IS 'Configuration file section with details about this provider'; 1362 COMMENT ON COLUMN legitimization_processes.provider_user_id 1363 IS 'Identifier for the user at the provider that was used for the legitimization. NULL if provider is unaware.'; 1364 COMMENT ON COLUMN legitimization_processes.provider_legitimization_id 1365 IS 'Identifier for the specific legitimization process at the provider. NULL if legitimization was not started.'; 1366 COMMENT ON COLUMN legitimization_processes.legitimization_measure_serial_id 1367 IS 'measure that enabled this setup, NULL if client voluntarily initiated the process'; 1368 COMMENT ON COLUMN legitimization_processes.redirect_url 1369 IS 'Where the user should be redirected for this external KYC process'; 1370 COMMENT ON COLUMN legitimization_processes.finished 1371 IS 'set to TRUE when the specific legitimization process is finished'; 1372 1373 CREATE TABLE kyc_attributes 1374 (kyc_attributes_serial_id INT8 GENERATED BY DEFAULT AS IDENTITY 1375 ,h_payto BYTEA PRIMARY KEY CHECK (LENGTH(h_payto)=32) 1376 REFERENCES wire_targets (wire_target_h_payto) 1377 ,legitimization_process_serial_id INT8 1378 REFERENCES legitimization_processes (legitimization_process_serial_id) 1379 DEFAULT NULL 1380 ,collection_time INT8 NOT NULL 1381 ,expiration_time INT8 NOT NULL 1382 ,trigger_outcome_serial INT8 NOT NULL 1383 REFERENCES legitimization_outcomes(outcome_serial_id) 1384 ,encrypted_attributes BYTEA NOT NULL 1385 ) PARTITION BY HASH (h_payto); 1386 1387 COMMENT ON COLUMN kyc_attributes.h_payto 1388 IS 'identifies the account this is about'; 1389 COMMENT ON COLUMN kyc_attributes.legitimization_process_serial_id 1390 IS 'serial ID of the legitimization process that resulted in these attributes, NULL if the attributes are from a form directly supplied by the account owner via a form'; 1391 COMMENT ON COLUMN kyc_attributes.collection_time 1392 IS 'when were these attributes collected'; 1393 COMMENT ON COLUMN kyc_attributes.expiration_time 1394 IS 'when are these attributes expected to expire'; 1395 COMMENT ON COLUMN kyc_attributes.trigger_outcome_serial 1396 IS 'ID of the outcome that was returned by the AML program based on the KYC data collected'; 1397 COMMENT ON COLUMN kyc_attributes.encrypted_attributes 1398 IS 'encrypted JSON object with the attribute data the check provided'; 1399 1400 CREATE TABLE aml_history 1401 (aml_history_serial_id INT8 GENERATED BY DEFAULT AS IDENTITY 1402 ,h_payto BYTEA CHECK (LENGTH(h_payto)=32) 1403 REFERENCES wire_targets (wire_target_h_payto) 1404 ,outcome_serial_id INT8 NOT NULL 1405 REFERENCES legitimization_outcomes (outcome_serial_id) 1406 ,justification TEXT NOT NULL 1407 ,decider_pub BYTEA CHECK (LENGTH(decider_pub)=32) 1408 ,decider_sig BYTEA CHECK (LENGTH(decider_sig)=64); 1409 1410 COMMENT ON TABLE aml_history 1411 IS 'Records decisions by AML staff with the respective signature and free-form justification.'; 1412 COMMENT ON COLUMN aml_history.outcome_serial_id 1413 IS 'Actual outcome for the account (included in what decider_sig signs over)'; 1414 COMMENT ON COLUMN aml_history.decider_sig 1415 IS 'Signature key of the staff member affirming the AML decision; of type AML_DECISION'; 1416 1417 CREATE TABLE kyc_events 1418 (kyc_event_serial_id INT8 GENERATED BY DEFAULT AS IDENTITY 1419 ,event_timestamp INT8 NOT NULL 1420 ,event_type TEXT NOT NULL); 1421 1422 COMMENT ON TABLE kyc_events 1423 IS 'Records of key events for statistics. Populated via triggers.'; 1424 COMMENT ON COLUMN kyc_events.event_type 1425 IS 'Name of the event, such as account-open or sar-filed'; 1426 1427 CREATE INDEX kyc_event_index 1428 ON kyc_events(event_type,event_timestamp); 1429 1430 1431 The ``jmeasures`` JSON in the ``legitimization_measures`` 1432 table is of type `LegitimizationMeasures`. 1433 1434 The ``jnew_rules`` JSON in the ``legitimization_outcomes`` 1435 table is of type `LegitimizationRuleSet`. 1436 1437 The ``jproperties`` JSON in the ``legitimization_outcomes`` table is of 1438 type `AccountProperties`. 1439 1440 1441 KYC forms 1442 ^^^^^^^^^ 1443 1444 The KYC SPA run by clients needs to support three TYPEs of checks. INFO is 1445 only about displaying the provided information, LINK is about setting up an 1446 exteral KYC check and redirecting there. FORM is about displaying a particular 1447 (HTML) form to the user and POSTing the entered information directly with the 1448 exchange. Here we describe the forms that must be supported: 1449 1450 * **CHOICE**: Asks the client a multiple-choice question. The context must 1451 include "choices: string[]" with a list of choices to show. Used, for 1452 example, to ask a client if they are an individual or a business. The 1453 resulting HTML FORM field name must be "choice" and it must be mapped to 1454 strings from the choices list. 1455 1456 * **UPLOAD**: Asks the client to upload a single file. 1457 The context must include a ``validity_duration`` which 1458 will be converted to the ``expiration_time`` for 1459 the uploaded data. The context may furthermore include 1460 ``extensions?: string[]`` with a list of allowed file extensions the client's 1461 file must end with (e.g. "png", "pdf", "gif"). In the absence of this 1462 context, any file may be uploaded. The context may also include a 1463 ``size_limit?: Integer`` with the maximum file size in bytes that can be 1464 uploaded. The resulting HTTP POST should provide at least two fields, "filename" and 1465 "filedata". "filename" must be set to the basename of the original file (to 1466 the extend that it is available), and "filedata" to the base64-encoding of 1467 the uploaded data. 1468 1469 As with other SPA checks, the KYC form should also show 1470 the description of the check. 1471 1472 1473 Merchant modifications 1474 ^^^^^^^^^^^^^^^^^^^^^^ 1475 1476 A new setting is required where the merchant backend can be configured for a 1477 business (default) or individual. 1478 1479 We introduce new ``kyc_ok``, ``aml_decision``, ``kyc_timestamp`` and 1480 ``exchange_kyc_serial`` fields into a new table ``merchant_kyc`` with primary 1481 keys ``exchange_url`` and ``account_serial``. This status is updated whenever 1482 a deposit is created or tracked, or whenever the mechant backend receives a 1483 ``/kyc-check/`` response from the exchange. Initially, 1484 ``exchange_kyc_serial`` is zero, indicating that the merchant has not yet made 1485 any deposits and thus does not have an account at the exchange. 1486 1487 A new private endpoint ``/kyc`` is introduced which allows frontends to 1488 request the ``/kyc`` status of any configured account (including with long 1489 polling). If the KYC status is negative or the ``kyc_timestamp`` not recent 1490 (say older than one month), the merchant backend will re-check the KYC status 1491 at the exchange (and update its cached status). The endpoint then returns 1492 either that the KYC is OK, or information (same as from the exchange endpoint) 1493 to begin the KYC process. 1494 1495 The merchant backend uses the new field to remember that a KYC is pending 1496 (after detection in ``taler-merchant-depositcheck``) and the SPA then shows a 1497 notification whenever the staff is logged in to the system. The notification 1498 can be hidden for the current day (remembered in local storage). 1499 1500 The notification links to a (new) KYC status page. When opened, the KYC SPA 1501 first re-checks the KYC status with the exchange. If the KYC is still 1502 unfinished, that SPA will show forms, links or contact information to begin 1503 the KYC process (for example, redirecting to the OAuth 2.0 login page of the 1504 legitimization resource server), otherwise it shows that the KYC process is 1505 done. If the KYC is unfinished, the merchant SPA should use long-polling on 1506 the KYC status on this page to ensure it is always up-to-date, and change to 1507 ``KYC satisfied`` should the long-poller return with positive news. 1508 1509 .. note:: 1510 1511 Semi-related: The TMH_setup_wire_account() is changed to use 1512 128-bit salt values (to keep ``deposits`` table small) and checks for salt 1513 to be well-formed should be added "everywhere". 1514 1515 1516 1517 Bank requirements 1518 ^^^^^^^^^^^^^^^^^ 1519 1520 The exchange primarily requires a KYC provider to be operated by the 1521 bank that offers an endpoint for with an API implemented by one of 1522 the logic plugins (and the respective legitimization configuration). 1523 1524 1525 Logic plugins 1526 ^^^^^^^^^^^^^ 1527 1528 The ``$PROVIDER_SECTION`` is based on the name of the configuration section, 1529 not on the name of the logic plugin (that we call ``$LOGIC``). Using the 1530 configuration section, the exchange then determines the logic plugin to use. 1531 1532 This section describes the general API for all of the supported KYC providers, 1533 as well as some details of how this general API could be implemented by the 1534 logic for different APIs. 1535 1536 1537 General KYC Logic Plugin API 1538 ---------------------------- 1539 1540 This section provides a sketch of the proposed API for the KYC logic plugins. 1541 1542 * initiation of KYC check (``kyc-check``): 1543 1544 - inputs: 1545 + provider_section (for additional configuration) 1546 + h_payto 1547 - outputs: 1548 + success/provider-failure 1549 + redirect URL (or NULL) 1550 + provider_user_id (or NULL) 1551 + provider_legitimization_id (or NULL) 1552 1553 * KYC status check (``kyc-proof``): 1554 1555 - inputs: 1556 + provider_section (for additional configuration) 1557 + h_payto 1558 + provider_user_id (or NULL) 1559 + provider_legitimization_id (or NULL) 1560 - outputs: 1561 + success/pending/user-aborted/user-failure/provider-failure status code 1562 + HTML response for end-user 1563 1564 * Webhook notification handler (``kyc-webhook``): 1565 1566 - inputs: 1567 + HTTP method (GET/POST) 1568 + rest of URL (after provider_section) 1569 + HTTP body (if applicable!) 1570 - outputs: 1571 + success/pending/user-aborted/user-failure/provider-failure status code 1572 + h_payto (for DB status update) 1573 + HTTP response to be returned to KYC provider 1574 1575 The plugins do not directly interact with the database, the caller sets the 1576 expiration on ``success`` and also updates ``provider_user_id`` and 1577 ``provider_legitimization_id`` in the tables as required. 1578 1579 1580 For the webhook, we need a way to lookup ``h_payto`` by other data, so the 1581 KYC logic plugin API should be provided a method lookup with: 1582 1583 - inputs: 1584 + ``provider_section`` 1585 + ``provider_legitimization_id`` 1586 - outputs: 1587 + ``h_payto`` 1588 + ``legitimization_process_row`` 1589 1590 1591 OAuth 2.0 specifics 1592 ------------------- 1593 1594 In terms of configuration, the OAuth 2.0 logic requires the respective client 1595 credentials to be configured apriori to enable access to the legitimization 1596 service. 1597 1598 For the ``/kyc-check/`` endpoint, the OAuth 2.0 logic may need to create and 1599 store a nonce to be used during ``/kyc-proof/``, depending on the OAuth 1600 variant used. This may require another exchange table. The OAuth 2.0 process 1601 must then be set up to end at the new ``/kyc-proof/$PROVIDER_ID/`` endpoint. 1602 1603 This ``/kyc-proof/oauth2/`` endpoint must query the OAuth 2.0 server using the 1604 ``code`` argument provided as a query parameter. Based on the result, it then 1605 updates the KYC table of the exchange with the legitimization status and 1606 returns a human-readable KYC status page. 1607 1608 The ``/kyc-webhook/`` is not applicable. 1609 1610 1611 Persona specifics 1612 ----------------- 1613 1614 We would use the hosted flow. Endpoints return a ``request-id``, which we should 1615 log for diagnosis. 1616 1617 For ``/kyc-check/``: 1618 1619 * Post to ``/api/v1/accounts`` using ``reference-id`` set to our ``h_payto``. 1620 Returns ``id`` (account_id). 1621 1622 * Create ``/verify`` endpoint using ``template-id`` (from configuration), 1623 and ``account_id`` (from previous step) and a ``reference-id`` (use 1624 the ``legitimization_serial_id`` for the new process). Set 1625 ``redirect-uri`` to ``/kyc-proof/$PROVIDER_ID/``. However, we cannot 1626 rely on the user clicking this, so we must also configure a webhook. 1627 The request returns a '``verification-id``. That we store under 1628 the ``provider_legitimization_id`` in the database. 1629 1630 For ``/kyc-proof/``: 1631 1632 * Use the ``/api/v1/verifications`` endpoint to get the verification 1633 status. Requires the ``verification-id`` from the previous step. 1634 Results include: created/pending/completed/expired (aborted)/failed. 1635 1636 For ``/kyc-webhook/``: 1637 1638 * The webhook is authenticated using a shared secret, which should 1639 be in the configuration. So all we should have to do is parse 1640 the POSTed body to find the status and the ``verification-id`` to 1641 lookup ``h_payto`` and return the result. 1642 1643 1644 KYC AID specifics 1645 ----------------- 1646 1647 For ``/kyc-check/``: 1648 1649 * Post to ``/applicants`` with a type (person or company) to 1650 obtain ``applicant_id``. Store that under ``provider_user_id``. 1651 ISSUE: *we* need to get the company_name, business_activity_id 1652 and registration_country before this somehow! 1653 1654 * start with create form URL ``/forms/$FORM_ID/urls`` 1655 providing our ``h_payto`` as the ``external_applicant_id``, 1656 using the ``applicant_id`` from above, 1657 and the ``/kyc-proof/$PROVIDER_ID`` for the ``redirect_url``. 1658 1659 * redirect customer to the ``form_url``, 1660 store the ``verification_id`` under ``provider_legitimization_id`` 1661 in the database. 1662 1663 For ``/kyc-proof/``: 1664 1665 * Not needed, just return an error. 1666 1667 For ``/kyc-webhook/``: 1668 1669 * For security, we should probably simply trigger the GET on 1670 ``/verifications/{verification_id}`` to not trust an unsigned POST 1671 to tell us anything for sure. The result is then returned. 1672 1673 1674 Types of KYC events 1675 ^^^^^^^^^^^^^^^^^^^ 1676 1677 The ``/aml/$OFFICER_PUB/kyc-statistics`` endpoint exposes statistics for 1678 various KYC event types. 1679 1680 We will initially support the use of the following types of KYC events in the 1681 SPA (and have a dialog to show the total number of any of these for any 1682 specified time range): 1683 1684 * account-open 1685 * account-closed 1686 * voluntary-sar 1687 * mandatory-sar 1688 * pep-started 1689 * pep-ended 1690 * risky-started 1691 * risky-ended 1692 * account-frozen 1693 * account-unfrozen 1694 1695 Based on these, the SPA should also be albe to show active 1696 statistics (for any given timestamp) on the total number of: 1697 1698 * open accounts 1699 * frozen accounts 1700 * high-risk accounts 1701 * PEPs served 1702 1703 .. note:: 1704 1705 This can be done by simply running the queries with 1706 a start time of zero and subtracting. 1707 1708 1709 Alternatives 1710 ============ 1711 1712 We could also store the access token (returned by OAuth 2.0), but that seems 1713 slightly more dangerous and given the close business relationship is 1714 unnecessary. Furthermore, not all APIs offer this. 1715 1716 We could extend the KYC logic API to return key attributes about the user 1717 (such as legal name, phone number, address, etc.) which we could then sign and 1718 return to the user. This would be useful in P2P payments to identify the 1719 origin of an invoice. However, we might want to be careful to not disclose 1720 the key attributes via the API by accident. This could likely be done by 1721 limiting access to the respective endpoint to messages with a signature by the 1722 reserve private key (which is the only case where we care to certify things 1723 anyway). 1724 1725 1726 Drawbacks 1727 ========= 1728 1729 1730 Discussion / Q&A 1731 ================ 1732 1733 (This should be filled in with results from discussions on mailing lists / personal communication.) 1734 1735 1736 If you have questions, remarks or suggestions regarding this information, 1737 please feel free to leave a comment at our 1738 `TALER Integration Community Hub <https://ich.taler.net/t/gnu-taler-exchange-documentation/78>`_.