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