taler-docs

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

023-taler-kyc.rst (74122B)


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