From 51f17bc444a8604253e22c55d09e59c1f871f563 Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Fri, 19 Apr 2024 15:00:08 +0200 Subject: improve KYC spec --- design-documents/023-taler-kyc.rst | 180 +++++++++++++++++++------------------ 1 file changed, 95 insertions(+), 85 deletions(-) diff --git a/design-documents/023-taler-kyc.rst b/design-documents/023-taler-kyc.rst index c41a3695..6ace74cb 100644 --- a/design-documents/023-taler-kyc.rst +++ b/design-documents/023-taler-kyc.rst @@ -46,6 +46,13 @@ Taler needs to take *measures* based on the following primary *triggers*: * Import of new sanctions lists and triggering of measures against matches of existing customer records against the list +For the different operation types, there can be both soft +and hard limits. Soft limits are those that the customer +may raise by providing data and passing KYC checks. +Hard limits cannot be lifted, for example because an +exchange forbids crossing those limits in its terms of +service for all customers. + Process requirements ^^^^^^^^^^^^^^^^^^^^ @@ -239,66 +246,63 @@ New Endpoints .. http:get:: /kyc-check/$REQUIREMENT_ROW/$H_PAYTO Checks the KYC status of a particular payment target and possibly begins the - KYC process. This endpoint is used by wallets or merchants that have been - told about a KYC requirement and now want to check if the KYC requirement - has been fulfilled. Long-polling may be used to instantly observe a change - in the KYC requirement status. - - The ``/kyc-check/`` endpoint is based on the legitimization requirements - serial number. FIXME: is this still OK? - - Access is ``authenticated`` by also passing the hash of the payto://-URI. - (Weak authentication is acceptable, as the KYC status or the ability to - initiate a KYC process are not very sensitive.) Given this triplet, the - ``/kyc-check/`` endpoint returns either the (positive) KYC status or redirects - the client (202) to the next required stage of the KYC process. The - redirection must be for an HTTP(S) endpoint to be triggered via a simple HTTP - GET. It must always be the same endpoint for the same client, as the - wallet/merchant backend are not required to check for changes to this - endpoint. + KYC process. This endpoint is typically used by wallets or merchants that + have been told about a KYC requirement and now want to check if the KYC + requirement has been fulfilled. Long-polling may be used to instantly + observe a change in the KYC requirement status. + + The ``/kyc-check/`` endpoint is based on the legitimization measure's + serial number. It is returned in `KycNeededRedirect` responses via + the ``requirement_row`` field together with the ``h_payto``. + Access is *authenticated* by also passing the hash of the payto://-URI. + .. note:: + + Weak authentication is acceptable, as the KYC status or the ability to + initiate a KYC process are not very sensitive. -FIXME: update /kyc-check/ endpoint to expose *public* outcomes of previous -checks (such as hard withdrawal limits)! + Given a valid pair of requirement row and payto-hash, the ``/kyc-check/`` + endpoint returns either just the KYC status or redirects the client (202) to + the next required stage of the KYC process. The redirection must be for an + HTTP(S) endpoint to be triggered via a simple HTTP GET. It must always be + the same endpoint for the same client, as the wallet/merchant backend are + not required to check for changes to this endpoint. Clients that received a + 202 status code may repeat the request and use long-polling to detect a + change of the HTTP status. **Request:** :query timeout_ms=NUMBER: *Optional.* If specified, the exchange will - wait up to ``timeout_ms`` milliseconds if the payment target - is currently not legitimized. Ignored if the payment target - is already legitimized. Note that the legitimization would be - triggered by another request to the same endpoint with a valid - ``token``. + wait up to ``timeout_ms`` milliseconds if the requirement continues + to be mandatory provisioning of KYC data by the client. + Ignored if the HTTP status code is already `200 Ok`. Note that + clients cannot long-poll for AML staff actions, so status information + about an account being under AML review needs to be requested + periodically. **Response:** :http:statuscode:`200 Ok`: - The KYC operation succeeded, the exchange confirms that the - payment target already authorized to transact. - The response will be an `AccountKycStatus` object. + No mandatory KYC actions are required by the client at this time. + The client *may* still visit the KYC URL to initiate voluntary checks. + The response will be an `AccountKycStatus` object which specifies + restrictions that currently apply to the account. If the + client attempts to exceed *soft* limits, the status may change + to a `202 Accepted`. Hard limits cannot be lifted by passing KYC checks. :http:statuscode:`202 Accepted`: - The user should be redirected to the provided location to perform + The account holder performed an operation that would have crossed + *soft* limits and must be redirected to the provided location to perform the required KYC checks to satisfy the legal requirements. Afterwards, the ``/kyc-check/`` request should be repeated to check whether the user has completed the process. - The response will be an `AccountKycRedirect` object. + The response will be an `AccountKycStatus` object. :http:statuscode:`204 No content`: The exchange is not configured to perform KYC and thus the legal requirements are already satisfied. - :http:statuscode:`402 Payment Required`: - The client must pay the KYC fee for the KYC process. - **This is currently not implemented, see #7365.** :http:statuscode:`403 Forbidden`: - The provided hash does not match the payment target. + The provided hash does not match the requirement row. :http:statuscode:`404 Not found`: - The payment target is unknown. - :http:statuscode:`451 Unavailable for Legal Reasons`: - The transaction cannot be completed due to AML rules. - Thus, the operation is currently not stuck on KYC, but - on exchange staff performing their AML review. The user - should be told to wait and/or contact the exchange operator - if the situation persists. - The response will be a `AccountAmlBlocked` object. + The requirement row is unknown. **Details:** @@ -306,68 +310,71 @@ checks (such as hard withdrawal limits)! interface AccountKycStatus { - // Details about the KYC check that the user - // passed. - kyc_details: KycDetails; - // Current time of the exchange, used as part of // what the exchange signs over. now: Timestamp; - // EdDSA signature of the exchange affirming the account - // is KYC'ed, must be of purpose - // ``TALER_SIGNATURE_EXCHANGE_ACCOUNT_SETUP_SUCCESS`` - // and over ``TALER_AccountSetupStatusSignaturePS``. - exchange_sig: EddsaSignature; - - // public key used to create the signature. - exchange_pub: EddsaPublicKey; - - // Current AML state for the target account. Non-zero - // values indicate that the transfer is blocked due to - // AML enforcement. - aml_status: Integer; - - } - - .. ts:def:: AccountKycRedirect - - interface AccountKycRedirect { + // Current AML state for the target account. True if + // operations are not happening due to staff processing + // paperwork *or* due to legal requirements (so the + // client cannot do anything but wait). + // + // Note that not every AML staff action may be legally + // exposed to the client, so this is merely a hint that + // a client should be told that AML staff is currently + // reviewing the account. AML staff *may* review + // accounts without this flag being set! + aml_review: boolean; // URL that the user should open in a browser to - // proceed with the KYC process. + // proceed with the KYC process (optional if + // the status type is 200 Ok, mandatory if the + // HTTP status is 202 Accepted). kyc_url: string; - // Current AML state for the target account. Non-zero - // values indicate that the transfer is blocked due to - // AML enforcement. - aml_status: Integer; + // Array with limitations that currently apply to this + // account and that may be increased or lifted if the + // KYC check is passed. + // Note that additional limits *may* exist and not be + // communicated to the client. If such limits are + // reached, this *may* be indicated by the account + // going into ``aml_review`` state. However, it is + // also possible that the exchange may legally have + // to deny operations without being allowed to provide + // any justification. + // The limits should be used by the client to + // possibly structure their operations (e.g. withdraw + // what is possible below the limit, ask the user to + // pass KYC checks or withdraw the rest after the time + // limit is passed, warn the user to not withdraw too + // much or even prevent the user from generating a + // request that would cause it to exceed hard limits). + limits?: AccountLimit[]; } - .. ts:def:: AccountAmlBlocked + .. ts:def:: AccountLimit - interface AccountAmlBlocked { + interface AccountLimit { - // Current AML state for the target account. Non-zero - // values indicate that the transfer is blocked due to - // AML enforcement. - aml_status: Integer; + // Operation that is limited. + // Must be one of "WITHDRAW", "DEPOSIT", "P2P-RECEIVE" + // or "WALLET-BALANCE". + operation_type: string; - } - - .. ts:def:: KycDetails - - // Object that specifies which KYC checks are satisfied. - interface KycDetails { + // Timeframe during which the limit applies. + timeframe: RelativeTime; - // Keys are the names of the check(s). - // The values are for now always empty objects. + // Maximum amount allowed during the given timeframe. + // Zero if the operation is simply forbidden. + threshold: Amount; + // True if this is a soft limit that could be raised + // by passing KYC checks. + soft: boolean; } - .. http:get:: /kyc-spa/{$HASH,$FILENAME} A set of ``/kyc-spa/$HASH`` GET endpoints is created per client ``$HASH`` @@ -399,7 +406,9 @@ checks (such as hard withdrawal limits)! *If-None-Match*: The client MAY provide an ``If-None-Match`` header with an ETag. - :query timeout_ms=MILLISECONDS: *Optional.* If specified, the exchange will wait up to MILLISECONDS for a change to a more recent legitimization measure before returning a 304 Not Modified. + :query timeout_ms=MILLISECONDS: *Optional.* If specified, the exchange + will wait up to MILLISECONDS for a change to a more recent legitimization + measure before returning a 304 Not Modified status. **Response**: @@ -473,6 +482,7 @@ checks (such as hard withdrawal limits)! :http:statuscode:`304 Not Modified`: The KYC requirements did not change. + .. http:post:: /kyc-upload/$ID The ``/kyc-upload/$ID`` POST endpoint allows the SPA to upload -- cgit v1.2.3