taler-docs

Documentation for GNU Taler components, APIs and protocols
Log | Files | Refs | README | LICENSE

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>`_.