taler-docs

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

commit 829f3fbfc2572402117309c8fd459c955374eb77
parent bd8d01e89b8557eb5a29eb20a318cc44a90fdc6a
Author: Christian Grothoff <christian@grothoff.org>
Date:   Thu, 21 May 2026 23:04:13 +0200

refactor API: one file per endpoint

Diffstat:
Mcore/api-bank-account-directory.rst | 63++-------------------------------------------------------------
Mcore/api-bank-conversion-info.rst | 218++-----------------------------------------------------------------------------
Mcore/api-bank-integration.rst | 252++-----------------------------------------------------------------------------
Mcore/api-bank-revenue.rst | 106++-----------------------------------------------------------------------------
Mcore/api-bank-transfer.rst | 198++-----------------------------------------------------------------------------
Mcore/api-bank-wire.rst | 655++-----------------------------------------------------------------------------
Mcore/api-challenger.rst | 504++-----------------------------------------------------------------------------
Mcore/api-corebank.rst | 1741++-----------------------------------------------------------------------------
Mcore/api-ebisync.rst | 94+++----------------------------------------------------------------------------
Mcore/api-mailbox.rst | 314++-----------------------------------------------------------------------------
Mcore/api-taldir.rst | 208++-----------------------------------------------------------------------------
Acore/bank-account-directory/get-config.rst | 27+++++++++++++++++++++++++++
Acore/bank-account-directory/get-search.rst | 34++++++++++++++++++++++++++++++++++
Acore/bank-conversion-info/get-cashin-rate.rst | 50++++++++++++++++++++++++++++++++++++++++++++++++++
Acore/bank-conversion-info/get-cashout-rate.rst | 49+++++++++++++++++++++++++++++++++++++++++++++++++
Acore/bank-conversion-info/get-config.rst | 45+++++++++++++++++++++++++++++++++++++++++++++
Acore/bank-conversion-info/get-rate.rst | 15+++++++++++++++
Acore/bank-conversion-info/post-conversion-rate.rst | 54++++++++++++++++++++++++++++++++++++++++++++++++++++++
Acore/bank-integration/get-config.rst | 34++++++++++++++++++++++++++++++++++
Acore/bank-integration/get-withdrawal-operation-WITHDRAWAL_ID.rst | 125+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Acore/bank-integration/post-withdrawal-operation-WITHDRAWAL_ID-abort.rst | 22++++++++++++++++++++++
Acore/bank-integration/post-withdrawal-operation-WITHDRAWAL_ID.rst | 67+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Acore/bank-revenue/get-config.rst | 30++++++++++++++++++++++++++++++
Acore/bank-revenue/get-history.rst | 74++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Acore/bank-transfer/get-config.rst | 41+++++++++++++++++++++++++++++++++++++++++
Acore/bank-transfer/post-registration.rst | 119+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Acore/bank-transfer/post-unregistration.rst | 35+++++++++++++++++++++++++++++++++++
Acore/bank-wire/get-account-check.rst | 30++++++++++++++++++++++++++++++
Acore/bank-wire/get-config.rst | 35+++++++++++++++++++++++++++++++++++
Acore/bank-wire/get-history-incoming.rst | 156+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Acore/bank-wire/get-history-outgoing.rst | 77+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Acore/bank-wire/get-transfers-ROW_ID.rst | 60++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Acore/bank-wire/get-transfers.rst | 78++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Acore/bank-wire/post-admin-add-incoming.rst | 56++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Acore/bank-wire/post-admin-add-kycauth.rst | 35+++++++++++++++++++++++++++++++++++
Acore/bank-wire/post-admin-add-mapped.rst | 38++++++++++++++++++++++++++++++++++++++
Acore/bank-wire/post-transfer.rst | 76++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Acore/challenger/get-authorize-NONCE.rst | 1+
Acore/challenger/get-config.rst | 49+++++++++++++++++++++++++++++++++++++++++++++++++
Acore/challenger/get-info.rst | 47+++++++++++++++++++++++++++++++++++++++++++++++
Acore/challenger/post-authorize-NONCE.rst | 84+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Acore/challenger/post-challenge-NONCE.rst | 93+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Acore/challenger/post-setup-CLIENT_ID.rst | 62++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Acore/challenger/post-solve-NONCE.rst | 84+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Acore/challenger/post-token.rst | 76++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Acore/corebank/any-accounts-USERNAME-conversion-info-star.rst | 6++++++
Acore/corebank/any-accounts-USERNAME-taler-revenue-star.rst | 4++++
Acore/corebank/any-accounts-USERNAME-taler-wire-gateway-star.rst | 6++++++
Acore/corebank/any-accounts-USERNAME-taler-wire-transfer-gateway-star.rst | 8++++++++
Acore/corebank/any-conversion-info-star.rst | 6++++++
Acore/corebank/any-conversion-rate-classes-CLASS_ID-conversion-info-star.rst | 6++++++
Acore/corebank/any-taler-integration-star.rst | 5+++++
Acore/corebank/any-taler-observability-star.rst | 6++++++
Acore/corebank/delete-accounts-USERNAME-token.rst | 14++++++++++++++
Acore/corebank/delete-accounts-USERNAME-tokens-TOKEN_ID.rst | 14++++++++++++++
Acore/corebank/delete-accounts-USERNAME.rst | 21+++++++++++++++++++++
Acore/corebank/delete-conversion-rate-classes-CLASS_ID.rst | 22++++++++++++++++++++++
Acore/corebank/get-accounts-USERNAME-cashouts-CASHOUT_ID.rst | 35+++++++++++++++++++++++++++++++++++
Acore/corebank/get-accounts-USERNAME-cashouts.rst | 42++++++++++++++++++++++++++++++++++++++++++
Acore/corebank/get-accounts-USERNAME-tokens.rst | 68++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Acore/corebank/get-accounts-USERNAME-transactions-TRANSACTION_ID.rst | 44++++++++++++++++++++++++++++++++++++++++++++
Acore/corebank/get-accounts-USERNAME-transactions.rst | 39+++++++++++++++++++++++++++++++++++++++
Acore/corebank/get-accounts-USERNAME.rst | 90+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Acore/corebank/get-accounts.rst | 111+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Acore/corebank/get-cashouts.rst | 49+++++++++++++++++++++++++++++++++++++++++++++++++
Acore/corebank/get-config.rst | 82+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Acore/corebank/get-conversion-rate-classes-CLASS_ID.rst | 62++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Acore/corebank/get-conversion-rate-classes.rst | 40++++++++++++++++++++++++++++++++++++++++
Acore/corebank/get-monitor.rst | 127+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Acore/corebank/get-public-accounts.rst | 55+++++++++++++++++++++++++++++++++++++++++++++++++++++++
Acore/corebank/get-withdrawals-WITHDRAWAL_ID.rst | 65+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Acore/corebank/patch-accounts-USERNAME-auth.rst | 34++++++++++++++++++++++++++++++++++
Acore/corebank/patch-accounts-USERNAME.rst | 71+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Acore/corebank/patch-conversion-rate-classes-CLASS_ID.rst | 26++++++++++++++++++++++++++
Acore/corebank/post-accounts-USERNAME-cashouts.rst | 78++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Acore/corebank/post-accounts-USERNAME-challenge-CHALLENGE_ID-confirm.rst | 29+++++++++++++++++++++++++++++
Acore/corebank/post-accounts-USERNAME-challenge-CHALLENGE_ID.rst | 40++++++++++++++++++++++++++++++++++++++++
Acore/corebank/post-accounts-USERNAME-token.rst | 52++++++++++++++++++++++++++++++++++++++++++++++++++++
Acore/corebank/post-accounts-USERNAME-transactions.rst | 54++++++++++++++++++++++++++++++++++++++++++++++++++++++
Acore/corebank/post-accounts-USERNAME-withdrawals-WITHDRAWAL_ID-abort.rst | 17+++++++++++++++++
Acore/corebank/post-accounts-USERNAME-withdrawals-WITHDRAWAL_ID-confirm.rst | 38++++++++++++++++++++++++++++++++++++++
Acore/corebank/post-accounts-USERNAME-withdrawals.rst | 54++++++++++++++++++++++++++++++++++++++++++++++++++++++
Acore/corebank/post-accounts.rst | 116+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Acore/corebank/post-conversion-rate-classes.rst | 66++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Acore/ebisync/get-config.rst | 29+++++++++++++++++++++++++++++
Acore/ebisync/get-submit.rst | 30++++++++++++++++++++++++++++++
Acore/ebisync/post-submit.rst | 32++++++++++++++++++++++++++++++++
Acore/mailbox/delete-ADDRESS.rst | 64++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Acore/mailbox/get-H_MAILBOX.rst | 35+++++++++++++++++++++++++++++++++++
Acore/mailbox/get-config.rst | 59+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Acore/mailbox/get-info-H_MAILBOX.rst | 58++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Acore/mailbox/post-H_MAILBOX.rst | 46++++++++++++++++++++++++++++++++++++++++++++++
Acore/mailbox/post-register.rst | 44++++++++++++++++++++++++++++++++++++++++++++
Acore/taldir/get-H_ALIAS.rst | 27+++++++++++++++++++++++++++
Acore/taldir/get-config.rst | 38++++++++++++++++++++++++++++++++++++++
Acore/taldir/get-register-H_ALIAS-PINTAN.rst | 27+++++++++++++++++++++++++++
Acore/taldir/post-H_ALIAS.rst | 32++++++++++++++++++++++++++++++++
Acore/taldir/post-register-ALIASTYPE.rst | 79+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
98 files changed, 4350 insertions(+), 4263 deletions(-)

diff --git a/core/api-bank-account-directory.rst b/core/api-bank-account-directory.rst @@ -41,65 +41,6 @@ The current protocol version is **v1**. * ``vXXX``: marker for features not yet targeted for release -.. http:get:: /config +.. include:: bank-account-directory/get-config.rst - Return the protocol version and configuration information about the bank. - - **Response:** - - :http:statuscode:`200 OK`: - The exchange responds with a `AccountDirectoryConfig` object. This request should - virtually always be successful. - - **Details:** - - .. ts:def:: AccountDirectoryConfig - - interface AccountDirectoryConfig { - // Name of the API. - name: "taler-bank-account-directory"; - - // libtool-style representation of the Bank protocol version, see - // https://www.gnu.org/software/libtool/manual/html_node/Versioning.html#Versioning - // - // The format is "current:revision:age". - version: string; - - // URN of the implementation (needed to interpret 'revision' in version). - implementation?: string; - } - -.. http:get:: /search - - Search for user accounts from user query. - - **Request:** - - :query keywords: - Textual search keywords. The fields matched depends on the bank. It can be a name, a login or any other identifier. - - **Response:** - - :http:statuscode:`200 OK`: - Response is a `Accounts`. - :http:statuscode:`204 No content`: - No accounts match this query. - - - **Details:** - - .. ts:def:: Accounts - - interface Accounts { - accounts: Account[]; - } - - .. ts:def:: Account - - interface Account { - // Formatted user information to be displayed. - display: string; - - // Full payto URI of this bank account. - payto_uri: string; - } +.. include:: bank-account-directory/get-search.rst diff --git a/core/api-bank-conversion-info.rst b/core/api-bank-conversion-info.rst @@ -44,224 +44,16 @@ The current protocol version is **v2**. -.. http:get:: /config +.. include:: bank-conversion-info/get-config.rst - Return the protocol version and configuration information about the bank. - - **Response:** - - :http:statuscode:`200 OK`: - Response is a `ConversionConfig`. - :http:statuscode:`501 Not implemented`: - This server does not support conversion, client should check config response. - - **Details:** - - .. ts:def:: ConversionConfig - - interface ConversionConfig { - // libtool-style representation of the Bank protocol version, see - // https://www.gnu.org/software/libtool/manual/html_node/Versioning.html#Versioning - // The format is "current:revision:age". - version: string; - - // Name of the API. - name: "taler-conversion-info"; - - // URN of the implementation (needed to interpret 'revision' in version). - // @since v4, may become mandatory in the future. - implementation?: string; - - // Currency used by this bank. - regional_currency: string; - - // How the bank SPA should render this currency. - regional_currency_specification: CurrencySpecification; - - // External currency used during conversion. - fiat_currency: string; - - // How the bank SPA should render this currency. - fiat_currency_specification: CurrencySpecification; - - // Global exchange rate between the regional currency and the fiat - // currency of the banking system. Use /rate to get the user specific - // rate. - conversion_rate: ConversionRate; - } - -.. http:get:: /rate - - Since protocol **v2**. - - This public endpoint allows clients to get the currenlty applied change rate between the regional currency and the fiat currency of the banking system for this exchange account. - Those informations should never be used to perform conversions use ``/cashin-rate`` and ``/cashout-rate`` instead. - Conversion rates can change at any time. Clients must deal with any resulting errors and call ``/cashin-rate`` or ``/cashout-rate`` again to use the new rates. - If ``cashin_ratio`` is zero, this means the account cannot cashin, and if ``cash_out`` ratio is zero, this means the account cannot cashout. - - **Response:** - - :http:statuscode:`200 OK`: - Response is a `ConversionRate`. - :http:statuscode:`501 Not implemented`: - This server does not support conversion. +.. include:: bank-conversion-info/get-rate.rst .. _cashin-rates: -.. http:get:: /cashin-rate - - This public endpoint allows clients to calculate - the exchange rate between the regional currency - and the fiat currency of the banking system. - - This endpoint shows how the bank would apply the cash-in - ratio and fee to one input amount. Typically, wallets would - request this endpoint before creating withdrawals that involve - a currency conversion. - - **Request:** - - :query amount_debit: this is the amount that the user will get - deducted from their fiat bank account. - - or - - :query amount_credit: this is the amount that the user will receive - in their regional bank account. - - **Response:** - - :http:statuscode:`200 OK`: - Response is a `CashinConversionResponse`. - :http:statuscode:`400 Bad request`: - * ``TALER_EC_GENERIC_PARAMETER_MISSING`` : none of the parameters have been provided. - * ``TALER_EC_GENERIC_PARAMETER_MALFORMED`` : both of the parameters have been provided or one of them is not a valid Taler amount. - * ``TALER_EC_GENERIC_CURRENCY_MISMATCH`` : the parameter is in the wrong currency. - :http:statuscode:`401 Unauthorized`: - Invalid credentials or missing rights. - :http:statuscode:`403 Forbidden`: - Missing rights. - :http:statuscode:`409 Conflict`: - The amount is too small to be converted because it produces an amount less than zero. - :http:statuscode:`501 Not implemented`: - This server does not support conversion, client should check config response. - - **Details:** - - .. ts:def:: CashinConversionResponse - - interface CashinConversionResponse { - // Amount that the user will get deducted from their fiat - // bank account, according to the 'amount_credit' value. - amount_debit: Amount; - // Amount that the user will receive in their regional - // bank account, according to 'amount_debit'. - amount_credit: Amount; - } +.. include:: bank-conversion-info/get-cashin-rate.rst .. _cashout-rates: -.. http:get:: /cashout-rate - - This public endpoint allows clients to calculate - the exchange rate between the regional currency - and the fiat currency of the banking system. - - This endpoint shows how the bank would apply the cash-out - ratio and fee to one input amount. Typically, frontends - ask this endpoint before creating cash-in operations. - - **Request:** - - :query amount_debit: this is the amount that the user will get - deducted from their regional bank account. - - or - - :query amount_credit: this is the amount that the user will receive - in their fiat bank account. - - **Response:** - - :http:statuscode:`200 OK`: - Response is a `CashoutConversionResponse`. - :http:statuscode:`400 Bad request`: - * ``TALER_EC_GENERIC_PARAMETER_MISSING`` : none of the parameters have been provided. - * ``TALER_EC_GENERIC_PARAMETER_MALFORMED`` : both of the parameters have been provided or one of them is not a valid Taler amount. - * ``TALER_EC_GENERIC_CURRENCY_MISMATCH`` : the parameter is in the wrong currency. - :http:statuscode:`401 Unauthorized`: - Invalid credentials or missing rights. - :http:statuscode:`403 Forbidden`: - Missing rights. - :http:statuscode:`409 Conflict`: - The amount is too small to be converted because it produces an amount less than zero. - :http:statuscode:`501 Not implemented`: - This server does not support conversion, client should check config response. - - **Details:** - - .. ts:def:: CashoutConversionResponse - - interface CashoutConversionResponse { - // Amount that the user will get deducted from their regional - // bank account, according to the 'amount_credit' value. - amount_debit: Amount; - // Amount that the user will receive in their fiat - // bank account, according to 'amount_debit'. - amount_credit: Amount; - } - -.. http:post:: /conversion-rate - - This endpoint allows the administrator to update the global exchange rate between the regional currency and the fiat currency of the banking system. Individual users can have different rate if they are part of an conversion rate classe. - - The conversion is calculated as follows: ``(amount * ratio - fee) / tiny_amount``. - - Only available to the administrator. - - **Request:** - - .. ts:def:: ConversionRate - - interface ConversionRate { - // Minimum fiat amount authorised for cashin before conversion - cashin_min_amount: Amount; - - // Exchange rate to buy regional currency from fiat - cashin_ratio: DecimalNumber; - - // Regional amount fee to subtract after applying the cashin ratio. - cashin_fee: Amount; - - // Smallest possible regional amount, converted amount is rounded to this amount - cashin_tiny_amount: Amount; - - // Rounding mode used during cashin conversion - cashin_rounding_mode: "zero" | "up" | "nearest"; - - // Minimum regional amount authorised for cashout before conversion - cashout_min_amount: Amount; - - // Exchange rate to sell regional currency for fiat - cashout_ratio: DecimalNumber; - - // Fiat amount fee to subtract after applying the cashout ratio. - cashout_fee: Amount; - - // Smallest possible fiat amount, converted amount is rounded to this amount - cashout_tiny_amount: Amount; - - // Rounding mode used during cashout conversion - cashout_rounding_mode: "zero" | "up" | "nearest"; - } - - **Response:** +.. include:: bank-conversion-info/get-cashout-rate.rst - :http:statuscode:`204 No content`: - Operation successful. - :http:statuscode:`401 Unauthorized`: - Invalid credentials or missing rights. - :http:statuscode:`403 Forbidden`: - Missing rights. - :http:statuscode:`501 Not implemented`: - This server does not support conversion, client should check config response. +.. include:: bank-conversion-info/post-conversion-rate.rst diff --git a/core/api-bank-integration.rst b/core/api-bank-integration.rst @@ -47,40 +47,7 @@ The current protocol version is **v5**. * ``vXXX``: marker for features not yet targeted for release -.. http:get:: /config - - Return the protocol version and configuration information about the bank. - - **Response:** - - :http:statuscode:`200 OK`: - The exchange responds with a `IntegrationConfig` object. This request should - virtually always be successful. - - **Details:** - - .. ts:def:: IntegrationConfig - - interface IntegrationConfig { - // Name of the API. - name: "taler-bank-integration"; - - // libtool-style representation of the Bank protocol version, see - // https://www.gnu.org/software/libtool/manual/html_node/Versioning.html#Versioning - // - // The format is "current:revision:age". - version: string; - - // URN of the implementation (needed to interpret 'revision' in version). - // @since **v2**, may become mandatory in the future. - implementation?: string; - - // Currency used by this bank. - currency: string; - - // How the bank SPA should render this currency. - currency_specification: CurrencySpecification; - } +.. include:: bank-integration/get-config.rst .. _wallet-wopid-withdrawing: @@ -94,221 +61,10 @@ Some user interaction (on the bank's websitei) creates a withdrawal operation record in the bank's database. The wallet can use a unique identifier for the withdrawal operation (the ``WITHDRAWAL_ID``) to interact with the withdrawal operation. -.. http:get:: /withdrawal-operation/$WITHDRAWAL_ID - - Query information about a withdrawal operation, identified by the ``WITHDRAWAL_ID``. - - **Request:** - - :query timeout_ms: *Optional.* - Timeout in milliseconds, for :ref:`long-polling <long-polling>`, to wait for operation state to be different from ``old_state``. Since protocol **v3**. - :query old_state: - *Optional.* Defaults to "pending". - :query long_poll_ms: *Optional.* - Deprecated in protocol **v3**. Use *timeout_ms* instead. - - **Response:** - - :http:statuscode:`200 OK`: - The withdrawal operation is known to the bank, and details are given - in the `BankWithdrawalOperationStatus` response body. - :http:statuscode:`404 Not found`: - The operation was not found. - - **Details:** - - .. ts:def:: BankWithdrawalOperationStatus - - interface BankWithdrawalOperationStatus { - // Current status of the operation - // pending: the operation is pending parameters selection (exchange and reserve public key) - // selected: the operations has been selected and is pending confirmation - // aborted: the operation has been aborted - // confirmed: the transfer has been confirmed and registered by the bank - // @since **v1** - status: "pending" | "selected" | "aborted" | "confirmed"; - - // Currency used for the withdrawal. - // MUST be present when amount is absent. - // @since **v2**, may become mandatory in the future. - currency?: string; - - // Amount that will be withdrawn with this operation - // (raw amount without fee considerations). Only - // given once the amount is fixed and cannot be changed. - // Optional since **v4**. - amount?: Amount; - - // Suggestion for the amount to be withdrawn with this - // operation. Given if a suggestion was made but the - // user may still change the amount. - // Optional since **v4**. - suggested_amount?: Amount; - - // Minimum amount that the wallet can choose to withdraw. - // Only applicable when the amount is not fixed. - // @since **v4**. - min_amount?: Amount; - - // Maximum amount that the wallet can choose to withdraw. - // Only applicable when the amount is not fixed. - // @since **v4**. - max_amount?: Amount; - - // The non-Taler card fees the customer will have - // to pay to the bank / payment service provider - // they are using to make the withdrawal in addition - // to the amount. - // @since **v4** - card_fees?: Amount; - - // Bank account of the customer that is debiting, as a - // full RFC 8905 ``payto`` URI. - sender_wire?: string; - - // Base URL of the suggested exchange. The bank may have - // neither a suggestion nor a requirement for the exchange. - // This value is typically set in the bank's configuration. - suggested_exchange?: string; - - // Base URL of an exchange that must be used. Optional, - // not given *unless* a particular exchange is mandatory. - // This value is typically set in the bank's configuration. - // @since **v4** - required_exchange?: string; - - // URL that the user needs to navigate to in order to - // complete some final confirmation (e.g. 2FA). - // Only applicable when ``status`` is ``selected`` or ``pending``. - // It may contain the withdrawal operation id. - confirm_transfer_url?: string; - - // Wire transfer types supported by the bank. - wire_types: string[]; - - // Reserve public key selected by the exchange, - // only non-null if ``status`` is ``selected`` or ``confirmed``. - // @since **v1** - selected_reserve_pub?: EddsaPublicKey; - - // Exchange account selected by the wallet; - // only non-null if ``status`` is ``selected`` or ``confirmed``. - // @since **v1** - selected_exchange_account?: string; - - // If true, tells the wallet not to allow the user to - // specify an amount to withdraw and to not provide - // any amount when registering with the withdrawal - // operation. The amount to withdraw will be set - // by the final ``/withdrawals/$WITHDRAWAL_ID/confirm`` step. - // @since **v5** - no_amount_to_wallet?: boolean; - - // @deprecated since **v1**, use ``status`` instead - // Indicates whether the withdrawal was aborted. - aborted: boolean; - - // @deprecated since **v1**, use ``status`` instead - // Has the wallet selected parameters for the withdrawal operation - // (exchange and reserve public key) and successfully sent it - // to the bank? - selection_done: boolean; - - // @deprecated since **v1**, use ``status`` instead - // The transfer has been confirmed and registered by the bank. - // Does not guarantee that the funds have arrived at the exchange already. - transfer_done: boolean; - } - - -.. http:post:: /withdrawal-operation/$WITHDRAWAL_ID - - This endpoint is used by the GNU Taler wallet to supply additional - details needed to complete a withdraw operation. - - **Request:** - - .. ts:def:: BankWithdrawalOperationPostRequest - - interface BankWithdrawalOperationPostRequest { - - // Reserve public key that should become the wire transfer - // subject to fund the withdrawal. - reserve_pub: EddsaPublicKey; - - // Full RFC 8905 (payto) address of the exchange account to be - // credited for the withdrawal. - selected_exchange: string; - - // Selected amount to be transferred. Optional if the - // backend already knows the amount. - // @since **v4** - amount?: Amount; - } - - **Response:** - - :http:statuscode:`200 OK`: - The bank has accepted the withdrawal operation parameters chosen by the wallet. - The response is a `BankWithdrawalOperationPostResponse`. - :http:statuscode:`404 Not found`: - The bank does not know about a withdrawal operation with the specified ``WITHDRAWAL_ID``. - :http:statuscode:`409 Conflict`: - * ``TALER_EC_BANK_UPDATE_ABORT_CONFLICT`` : the withdrawal has been aborted previously and can't be modified. - * ``TALER_EC_BANK_WITHDRAWAL_OPERATION_RESERVE_SELECTION_CONFLICT``: - The wallet selected a different exchange or reserve public key under the same withdrawal ID. - * ``TALER_EC_BANK_DUPLICATE_RESERVE_PUB_SUBJECT``: the reserve public key is already used. - * ``TALER_EC_BANK_UNKNOWN_ACCOUNT``: the selected exchange account was not found. - * ``TALER_EC_BANK_ACCOUNT_IS_NOT_EXCHANGE``: the selected account is not an exchange. - * ``TALER_EC_BANK_AMOUNT_DIFFERS`` : the specified amount will not work for this - withdrawal (since **v4**). - * ``TALER_EC_BANK_UNALLOWED_DEBIT`` : the account does not have sufficient funds or the amount is too low or too high (since **v4**). - - **Details:** - - .. ts:def:: BankWithdrawalOperationPostResponse - - interface BankWithdrawalOperationPostResponse { - // Current status of the operation - // pending: the operation is pending parameters selection (exchange and reserve public key) - // selected: the operations has been selected and is pending confirmation - // aborted: the operation has been aborted - // confirmed: the transfer has been confirmed and registered by the bank - status: "selected" | "aborted" | "confirmed"; - - // URL that the user needs to navigate to in order to - // complete some final confirmation (e.g. 2FA). - // - // Only applicable when ``status`` is ``selected`` or ``pending``. - // It may contain withdrawal operation id - confirm_transfer_url?: string; - - // @deprecated since **v1**, use ``status`` instead - // The transfer has been confirmed and registered by the bank. - // Does not guarantee that the funds have arrived at the exchange already. - transfer_done: boolean; - } - - -.. http:post:: /withdrawal-operation/$WITHDRAWAL_ID/abort - - Aborts ``WITHDRAWAL_ID`` operation. Has no effect on an already aborted - operation. This endpoint can be used by the wallet if the user aborts - the transaction, ensuring that the operation is also aborted at the - bank. - - Since protocol **v2**. +.. include:: bank-integration/get-withdrawal-operation-WITHDRAWAL_ID.rst - **Request:** - The request body is empty. +.. include:: bank-integration/post-withdrawal-operation-WITHDRAWAL_ID.rst - **Response:** - :http:statuscode:`204 No content`: - The withdrawal operation has been aborted. - :http:statuscode:`404 Not found`: - The withdrawal operation was not found. - :http:statuscode:`409 Conflict`: - The withdrawal operation has been confirmed previously and - can't be aborted. +.. include:: bank-integration/post-withdrawal-operation-WITHDRAWAL_ID-abort.rst diff --git a/core/api-bank-revenue.rst b/core/api-bank-revenue.rst @@ -44,36 +44,7 @@ The current protocol version is **v1**. * ``vXXX``: marker for features not yet targeted for release -.. http:get:: /config - - Return the protocol version and configuration information about the bank. - - **Response:** - - :http:statuscode:`200 OK`: - The exchange responds with a `RevenueConfig` object. This request should - virtually always be successful. - - **Details:** - - .. ts:def:: RevenueConfig - - interface RevenueConfig { - // Name of the API. - name: "taler-revenue"; - - // libtool-style representation of the Bank protocol version, see - // https://www.gnu.org/software/libtool/manual/html_node/Versioning.html#Versioning - // The format is "current:revision:age". - version: string; - - // Currency used by this gateway. - currency: string; - - // URN of the implementation (needed to interpret 'revision' in version). - // @since v0, may become mandatory in the future. - implementation?: string; - } +.. include:: bank-revenue/get-config.rst -------------- @@ -87,77 +58,4 @@ The bank library authenticates requests to the bank merchant API using Querying the transaction history -------------------------------- -.. http:get:: /history - - Return a list of transactions made to an account. - - The bank account is determined via the base URL and/or the - user name in the ``Authorization`` header. In fact, the transaction history - might come from a "virtual" account, where multiple real bank accounts are - merged into one history. - - Transactions are identified by an opaque ``row_id`` numerical identifier. Its semantics (including its sorting order) are determined by the bank server and are completely opaque to the client. - - **Request:** - - :query limit: *Optional.* - At most return the given number of results. Negative for descending by ``row_id``, positive for ascending by ``row_id``. Defaults to ``-20``. Since protocol v1. - :query offset: *Optional.* - Starting ``row_id`` for :ref:`pagination <row-id-pagination>`. Since protocol v1. - :query timeout_ms: *Optional.* - Timeout in milliseconds, for :ref:`long-polling <long-polling>`, to wait for at least one element to be shown. Only useful if *limit* is positive. Since protocol v1. - :query delta: *Optional.* - Deprecated in protocol **v1**. Use *limit* instead. - :query start: *Optional.* - Deprecated in protocol **v1**. Use *offset* instead. - :query long_poll_ms: *Optional.* - Deprecated in protocol **v1**. Use *timeout_ms* instead. - - **Response:** - - :http:statuscode:`200 OK`: - JSON object of type `RevenueIncomingHistory`. - :http:statuscode:`400 Bad request`: - Request malformed. The bank replies with an `ErrorDetail` object. - :http:statuscode:`401 Unauthorized`: - Authentication failed, likely the credentials are wrong. - :http:statuscode:`404 Not found`: - The endpoint is wrong or the user name is unknown. The bank replies with an `ErrorDetail` object. - - **Details:** - - .. ts:def:: RevenueIncomingHistory - - interface RevenueIncomingHistory { - // Array of incoming transactions. - incoming_transactions : RevenueIncomingBankTransaction[]; - - // Full payto URI to identify the receiver of funds. - // Credit account is shared by all incoming transactions - // as per the nature of the request. - credit_account: string; - } - - .. ts:def:: RevenueIncomingBankTransaction - - interface RevenueIncomingBankTransaction { - // Opaque identifier of the returned record. - row_id: SafeUint64; - - // Date of the transaction. - date: Timestamp; - - // Amount received before credit_fee. - amount: Amount; - - // Fee payed by the creditor. - // If not null, creditor actually received amount - credit_fee - // @since **v1** - credit_fee?: Amount; - - // Full payto URI to identify the sender of funds. - debit_account: string; - - // The wire transfer subject. - subject: string; - } +.. include:: bank-revenue/get-history.rst diff --git a/core/api-bank-transfer.rst b/core/api-bank-transfer.rst @@ -24,203 +24,12 @@ used by clients such as wallets to prepare wire transfers. This allows the use of wire-specific subject format or optimized alternating wire transfer flows, and enables the use of recurring wire transfers. -.. http:get:: /config - - Return the protocol version and configuration information about the adapter. - This specification corresponds to ``current`` protocol being version **1**. - - **Response:** - - :http:statuscode:`200 OK`: - The adapter responds with a `PreparedTransferConfig` object. This request - should virtually always be successful. - - **Details:** - - .. ts:def:: SubjectFormat - - type SubjectFormat = - | "SIMPLE" - | "URI" - | "CH_QR_BILL"; - - .. ts:def:: PreparedTransferConfig - - interface PreparedTransferConfig { - // Name of the API. - name: "taler-prepared-transfer"; - - // libtool-style representation of the protocol version, see - // https://www.gnu.org/software/libtool/manual/html_node/Versioning.html#Versioning - // The format is "current:revision:age". - version: string; - - // Currency used by this API. - currency: string; - - // URN of the implementation (needed to interpret 'revision' in version). - // @since v0, may become mandatory in the future. - implementation?: string; - - // Supported formats for registration, there must at least one. - supported_formats: SubjectFormat[]; - } +.. include:: bank-transfer/get-config.rst ----------------------- Prepared wire transfers ----------------------- -.. http:post:: /registration - - Register a public key for wire transfer use. - - This endpoint generate appropriate subjects to link a transfer to the - registered public key. - - Two public keys must be provided, the ``account_pub`` key is the key that - will forwarded to the exchange and the ``authorization_pub`` key will be - encoded inside the subject. - - For simple one time wire transfers, use the same key for both ``account_pub`` - and ``authorization_pub``. For recurrent transfers, use a single - ``authorization_pub`` for different ``account_pub``. - - If registered as ``recurrent`` the wire adapters will keep incoming transfers - reusing the same subject until a registration is performed, else it will - bounce. - - Registration with the same ``authorization_pu`` will replace the existing information registered for the key. - - **Request:** - - .. ts:def:: RegistrationRequest - - interface RegistrationRequest { - // Amount to transfer - credit_amount: Amount; - - // Transfer types - type: "reserve" | "kyc"; - - // Public key algorithm - alg: "EdDSA"; - - // Account public key for the exchange - account_pub: EddsaPublicKey; - - // Public key encoded inside the subject - authorization_pub: EddsaPublicKey; - - // Signature of the account_pub key using the authorization_pub private key - authorization_sig: EddsaSignature; - - // Whether the authorization_pub will be reused for recurrent transfers - // Disable bounces in case of authorization_pub reuse - recurrent: boolean; - } - - **Response:** - - :http:statuscode:`200 Ok`: - Response is a `RegistrationResponse`. - :http:statuscode:`400 Bad request`: - Input data was invalid. - :http:statuscode:`409 Conflict`: - * ``TALER_EC_BANK_DUPLICATE_RESERVE_PUB_SUBJECT``: the same reserve public key is already registered, you should retry using another key. - * ``TALER_EC_BANK_DERIVATION_REUSE``: derived subject is already used, you should retry using another key. - * ``TALER_EC_BANK_BAD_SIGNATURE``: signature is invalid. - - **Details:** - - .. ts:def:: TransferSubject - - // Union discriminated by the "type" field. - type TransferSubject = - | SimpleSubject - | UriSubject - | SwissQrBillSubject; - - .. ts:def:: SimpleSubject - - interface SimpleSubject { - // Subject for system accepting large subjects - type: "SIMPLE"; - - // Amount to transfer - credit_amount: Amount; - - // Encoded string containing either the full key and transfer type or a - // derived short subject - subject: string; - } - - .. ts:def:: UriSubject - - interface UriSubject { - // Subject for system accepting prepared payments - type: "URI"; - - // Amount to transfer - credit_amount: Amount; - - // Prepared payments confirmation URI - uri: string; - } - - .. ts:def:: SwissQrBillSubject - - interface SwissQrBillSubject { - // Subject for Swiss QR Bill - type: "CH_QR_BILL"; - - // Amount to transfer - credit_amount: Amount; - - // 27-digit QR Reference number - qr_reference_number: string; - } - - .. ts:def:: RegistrationResponse - - interface RegistrationResponse { - // The transfer subject encoded in all supported formats - subjects: TransferSubject[]; - - // Expiration date after which this subject is expected to be reused - expiration: Timestamp; - } - -.. http:post:: /unregistration - - Remove an existing registered public key for wire transfer use. - - Use this endpoint to free a derived subject or cancel a recurrent paiment. - - - **Request:** - - .. ts:def:: Unregistration - - interface Unregistration { - // Current timestamp in the ISO 8601 - timestamp: string; - - // Public key used for registration - authorization_pub: EddsaPublicKey; - - // Signature of the timestamp using the authorization_pub private key - // Prevent replay attack - authorization_sig: EddsaSignature; - } - - **Response:** +.. include:: bank-transfer/post-registration.rst - :http:statuscode:`204 No content`: - The registration have been deleted. - :http:statuscode:`400 Bad request`: - Input data was invalid. - :http:statuscode:`404 Not found`: - Unknown registration. - :http:statuscode:`409 Conflict`: - * ``TALER_EC_BANK_OLD_TIMESTAMP``: the timestamp is too old. - * ``TALER_EC_BANK_BAD_SIGNATURE``: signature is invalid. -\ No newline at end of file +.. include:: bank-transfer/post-unregistration.rst diff --git a/core/api-bank-wire.rst b/core/api-bank-wire.rst @@ -37,41 +37,7 @@ well as by the auditor to query incoming and outgoing transactions. This API is currently implemented by the Taler Demo Bank, as well as by LibEuFin. -.. http:get:: /config - - Return the protocol version and configuration information about the bank. - This specification corresponds to ``current`` protocol being version **5**. - - **Response:** - - :http:statuscode:`200 OK`: - The adapter responds with a `WireConfig` object. This request should - virtually always be successful. - - **Details:** - - .. ts:def:: WireConfig - - interface WireConfig { - // Name of the API. - name: "taler-wire-gateway"; - - // libtool-style representation of the Bank protocol version, see - // https://www.gnu.org/software/libtool/manual/html_node/Versioning.html#Versioning - // The format is "current:revision:age". - version: string; - - // Currency used by this gateway. - currency: string; - - // URN of the implementation (needed to interpret 'revision' in version). - // @since v0, may become mandatory in the future. - implementation?: string; - - // Whether implementation support account existence check - // @since **v4** - support_account_check: boolean; - } +.. include:: bank-wire/get-config.rst -------------- Authentication @@ -84,223 +50,12 @@ The bank library authenticates requests to the wire gateway via Making Transactions ------------------- -.. http:post:: /transfer +.. include:: bank-wire/post-transfer.rst + +.. include:: bank-wire/get-transfers.rst - Initiate a new wire transfer from the exchange's bank account, typically to a - merchant. - - The exchange's bank account is not included in the request, but instead - derived from the username in the ``Authorization`` header and/or the request - base URL. - - To make the API idempotent, the client must include a nonce. Requests with - the same nonce are rejected unless the request is the same. - - **Request:** - - .. ts:def:: TransferRequest - - interface TransferRequest { - // Nonce to make the request idempotent. Requests with the same - // ``request_uid`` that differs in any of the other fields - // are rejected. - request_uid: HashCode; - - // Amount to transfer. - amount: Amount; - - // Base URL of the exchange. Shall be included by the bank gateway - // in the appropriate section of the wire transfer details. - exchange_base_url: string; - - // Optional additional metadata to be stored in the transaction. - // Must match [a-zA-Z0-9-.:]{1, 40} - // @since **v5** - metadata?: string; - - // Wire transfer identifier chosen by the exchange, - // used by the merchant to identify the Taler order(s) - // associated with this wire transfer. - wtid: ShortHashCode; - - // The recipient's account identifier as a full payto URI. - credit_account: string; - } - - **Response:** - - :http:statuscode:`200 OK`: - The request has been correctly handled, so the funds have been transferred to - the recipient's account. The body is a `TransferResponse`. - :http:statuscode:`400 Bad request`: - Request malformed. The bank replies with an `ErrorDetail` object. - :http:statuscode:`401 Unauthorized`: - Authentication failed, likely the credentials are wrong. - :http:statuscode:`404 Not found`: - The endpoint is wrong or the user name is unknown. The bank replies with an `ErrorDetail` object. - :http:statuscode:`409 Conflict`: - * ``TALER_EC_BANK_TRANSFER_REQUEST_UID_REUSED``: an operation with the same ``request_uid`` but different details has been submitted before. - * ``TALER_EC_BANK_TRANSFER_WTID_REUSED``: an operation with the same ``wtid`` but a different ``request_uid`` has been submitted before. - - **Details:** - - .. ts:def:: TransferResponse - - interface TransferResponse { - // Timestamp that indicates when the wire transfer will be executed. - // In cases where the wire transfer gateway is unable to know when - // the wire transfer will be executed, the time at which the request - // has been received and stored will be returned. - // The purpose of this field is for debugging (humans trying to find - // the transaction) as well as for taxation (determining which - // time period a transaction belongs to). - timestamp: Timestamp; - - // Opaque ID of the wire transfer initiation performed by the bank. - // It is different from the /history endpoints row_id. - row_id: SafeUint64; - } - -.. http:get:: /transfers - - Return a list of transfers initiated from the exchange. - - The bank account of the exchange is determined via the base URL and/or the - user name in the ``Authorization`` header. The transfer history - might come from a "virtual" account, where multiple real bank accounts are - merged into one history. - - Since protocol **v3**. - - **Request:** - - :query limit: *Optional.* - At most return the given number of results. Negative for descending by - ``row_id``, positive for ascending by ``row_id``. Defaults to ``-20``. - :query offset: *Optional.* - Starting ``row_id`` for :ref:`pagination <row-id-pagination>`. - :query status: *Optional*. - Filters by status. - - **Response:** - - :http:statuscode:`200 OK`: - JSON object of type `TransferList`. - :http:statuscode:`204 No content`: - There are no transfers to report (under the given filter). - :http:statuscode:`400 Bad request`: - Request malformed. - :http:statuscode:`401 Unauthorized`: - Authentication failed, likely the credentials are wrong. - :http:statuscode:`404 Not found`: - The endpoint is wrong or the user name is unknown. - - **Details:** - - .. ts:def:: TransferList - - interface TransferList { - // Array of initiated transfers. - transfers: TransferListStatus[]; - - // Full payto:// URI to identify the sender of funds. - // This must be one of the exchange's bank accounts. - // Credit account is shared by all incoming transactions - // as per the nature of the request. - debit_account: string; - } - - .. ts:def:: TransferListStatus - - interface TransferListStatus { - // Opaque ID of the wire transfer initiation performed by the bank. - // It is different from the /history endpoints row_id. - row_id: SafeUint64; - - // Current status of the transfer - // pending: the transfer is in progress - // transient_failure: the transfer has failed but may succeed later - // permanent_failure: the transfer has failed permanently and will never appear in the outgoing history - // success: the transfer has succeeded and appears in the outgoing history - status: "pending" | "transient_failure" | "permanent_failure" | "success"; - - // Amount to transfer. - amount: Amount; - - // The recipient's account identifier as a full payto:// URI. - credit_account: string; - - // Timestamp that indicates when the wire transfer was executed. - // In cases where the wire transfer gateway is unable to know when - // the wire transfer will be executed, the time at which the request - // has been received and stored will be returned. - // The purpose of this field is for debugging (humans trying to find - // the transaction) as well as for taxation (determining which - // time period a transaction belongs to). - timestamp: Timestamp; - } - - -.. http:get:: /transfers/$ROW_ID - - Return the status of a transfer initiated from the exchange, identified by the ``ROW_ID``. - - Since protocol **v3**. - - **Response:** - - :http:statuscode:`200 OK`: - The transfer is known, and details are given in the `TransferStatus` response body. - :http:statuscode:`400 Bad request`: - Request malformed. - :http:statuscode:`401 Unauthorized`: - Authentication failed, likely the credentials are wrong. - :http:statuscode:`404 Not found`: - The transfer was not found. - - **Details:** - - .. ts:def:: TransferStatus - - interface TransferStatus { - // Current status of the transfer - // pending: the transfer is in progress - // transient_failure: the transfer has failed but may succeed later - // permanent_failure: the transfer has failed permanently and will never appear in the outgoing history - // success: the transfer has succeeded and appears in the outgoing history - status: "pending" | "transient_failure" | "permanent_failure" | "success"; - - // Optional unstructured messages about the transfer's status. Can be used to document the reasons for failure or the state of progress. - status_msg?: string; - - // Amount to transfer. - amount: Amount; - - // Base URL of the exchange. Shall be included by the bank gateway - // in the appropriate section of the wire transfer details. - exchange_base_url: string; - - // Optional additional metadata to be stored in the transaction. - // @since **v5** - metadata?: string; - - // Wire transfer identifier chosen by the exchange, - // used by the merchant to identify the Taler order(s) - // associated with this wire transfer. - wtid: ShortHashCode; - - // The recipient's account identifier as a full payto URI. - credit_account: string; - - // Timestamp that indicates when the wire transfer was executed. - // In cases where the wire transfer gateway is unable to know when - // the wire transfer will be executed, the time at which the request - // has been received and stored will be returned. - // The purpose of this field is for debugging (humans trying to find - // the transaction) as well as for taxation (determining which - // time period a transaction belongs to). - timestamp: Timestamp; - } + +.. include:: bank-wire/get-transfers-ROW_ID.rst -------------------------------- Querying the transaction history @@ -311,277 +66,17 @@ The exchange's bank account is derived from the username in the transaction history may come from a "virtual" account, where several real bank accounts are merged into a single history. -.. http:get:: /history/incoming - - Return a list of transactions made from or to the exchange. - - Incoming transactions must contain a valid reserve public key. If a bank - transaction does not conform to the right syntax, the wire gateway must not - report it to the exchange, and send funds back to the sender if possible. - - **Request:** - - :query limit: *Optional.* - At most return the given number of results. Negative for descending by ``row_id``, positive for ascending by ``row_id``. Defaults to ``-20``. Since protocol **v2**. - :query offset: *Optional.* - Starting ``row_id`` for :ref:`pagination <row-id-pagination>`. Since protocol **v2**. - :query timeout_ms: *Optional.* - Timeout in milliseconds, for :ref:`long-polling <long-polling>`, to wait for at least one element to be shown. Only useful if *limit* is positive. Since protocol **v2**. - :query delta: *Optional.* - Deprecated in protocol **v2**. Use *limit* instead. - :query start: *Optional.* - Deprecated in protocol **v2**. Use *offset* instead. - :query long_poll_ms: *Optional.* - Deprecated in protocol **v2**. Use *timeout_ms* instead. - - **Response:** - - :http:statuscode:`200 OK`: - JSON object of type `IncomingHistory`. - :http:statuscode:`204 No content`: - There are not transactions to report (under the given filter). - :http:statuscode:`400 Bad request`: - Request malformed. The bank replies with an `ErrorDetail` object. - :http:statuscode:`401 Unauthorized`: - Authentication failed, likely the credentials are wrong. - :http:statuscode:`404 Not found`: - The endpoint is wrong or the user name is unknown. The bank replies with an `ErrorDetail` object. - - **Details:** - - .. ts:def:: IncomingHistory - - interface IncomingHistory { - // Array of incoming transactions. - incoming_transactions: IncomingBankTransaction[]; - - // Full payto URI to identify the receiver of funds. - // This must be one of the exchange's bank accounts. - // Credit account is shared by all incoming transactions - // as per the nature of the request. - credit_account: string; - } - - .. ts:def:: IncomingBankTransaction - - // Union discriminated by the "type" field. - type IncomingBankTransaction = - | IncomingKycAuthTransaction - | IncomingReserveTransaction - | IncomingWadTransaction; - - .. ts:def:: IncomingKycAuthTransaction - - // Since protocol **v1**. - interface IncomingKycAuthTransaction { - type: "KYCAUTH"; - - // Opaque identifier of the returned record. - row_id: SafeUint64; - - // Date of the transaction. - date: Timestamp; - - // Amount received before credit_fee. - amount: Amount; - - // Fee paid by the creditor. - // If not null, creditor actually received amount - credit_fee - // @since **v3** - credit_fee?: Amount; - - // Full payto URI to identify the sender of funds. - debit_account: string; - - // The account public key extracted from the transaction details. - account_pub: EddsaPublicKey; - - // The authorization public key used for mapping - // @since **v5** - authorization_pub?: EddsaPublicKey; - - // Signature of the account public key using the authorization private key - // @since **v5** - authorization_sig?: EddsaSignature; - } - - .. ts:def:: IncomingReserveTransaction - - interface IncomingReserveTransaction { - type: "RESERVE"; - - // Opaque identifier of the returned record. - row_id: SafeUint64; - - // Date of the transaction. - date: Timestamp; - - // Amount received before credit_fee. - amount: Amount; - - // Fee payed by the creditor. - // If not null, creditor actually received amount - - // @since **v3** - credit_fee?: Amount; - - // Full payto URI to identify the sender of funds. - debit_account: string; - - // The reserve public key extracted from the transaction details. - reserve_pub: EddsaPublicKey; - - // The authorization public key used for mapping - // @since **v5** - authorization_pub?: EddsaPublicKey; - - // Signature of the reserve public key using the authorization private key - // @since **v5** - authorization_sig?: EddsaSignature; - } - - .. ts:def:: IncomingWadTransaction - - interface IncomingWadTransaction { - type: "WAD"; - - // Opaque identifier of the returned record. - row_id: SafeUint64; - - // Date of the transaction. - date: Timestamp; - - // Amount received before credit_fee. - amount: Amount; - - // Fee payed by the creditor. - // If not null, creditor actually received amount - credit_fee - // @since **v3** - credit_fee?: Amount; - - // Full payto URI to identify the sender of funds. - debit_account: string; - - // Base URL of the exchange that originated the wad. - origin_exchange_url: string; - - // The reserve public key extracted from the transaction details. - wad_id: WadId; - } - +.. include:: bank-wire/get-history-incoming.rst -.. http:get:: /history/outgoing - Return a list of transactions made by the exchange, typically to a merchant. - - **Request:** - - :query limit: *Optional.* - At most return the given number of results. Negative for descending by ``row_id``, positive for ascending by ``row_id``. Defaults to ``-20``. Since protocol **v2**. - :query offset: *Optional.* - Starting ``row_id`` for :ref:`pagination <row-id-pagination>`. Since protocol **v2**. - :query timeout_ms: *Optional.* - Timeout in milliseconds, for :ref:`long-polling <long-polling>`, to wait for at least one element to be shown. Only useful if *limit* is positive. Since protocol **v2**. - :query delta: *Optional.* - Deprecated in protocol **v2**. Use *limit* instead. - :query start: *Optional.* - Deprecated in protocol **v2**. Use *offset* instead. - :query long_poll_ms: *Optional.* - Deprecated in protocol **v2**. Use *timeout_ms* instead. - - **Response:** - - :http:statuscode:`200 OK`: - JSON object of type `OutgoingHistory`. - :http:statuscode:`204 No content`: - There are not transactions to report (under the given filter). - :http:statuscode:`400 Bad request`: - Request malformed. The bank replies with an `ErrorDetail` object. - :http:statuscode:`401 Unauthorized`: - Authentication failed, likely the credentials are wrong. - :http:statuscode:`404 Not found`: - The endpoint is wrong or the user name is unknown. The bank replies with an `ErrorDetail` object. - - **Details:** - - .. ts:def:: OutgoingHistory - - interface OutgoingHistory { - // Array of outgoing transactions. - outgoing_transactions: OutgoingBankTransaction[]; - - // Full payto URI to identify the sender of funds. - // This must be one of the exchange's bank accounts. - // Credit account is shared by all incoming transactions - // as per the nature of the request. - debit_account: string; - } - - .. ts:def:: OutgoingBankTransaction - - interface OutgoingBankTransaction { - // Opaque identifier of the returned record. - row_id: SafeUint64; - - // Date of the transaction. - date: Timestamp; - - // Amount transferred. - amount: Amount; - - // Fee paid by the debtor. - // If not null, debtor actually paid amount + debit_fee - // @since **v3** - debit_fee?: Amount; - - // Full payto URI to identify the receiver of funds. - credit_account: string; - - // The wire transfer ID in the outgoing transaction. - wtid: ShortHashCode; - - // Base URL of the exchange. - exchange_base_url: string; - - // Optional additional metadata. - // @since **v5** - metadata?: string; - } +.. include:: bank-wire/get-history-outgoing.rst ----------------- Wire Account APIs ----------------- -.. http:get:: /account/check - - Check account existence. - - Since protocol **v4**. - - **Request:** - - :query account: - Payto URI of the account. - - **Response:** - - :http:statuscode:`200 OK`: - JSON object of type `AccountInfo`. - :http:statuscode:`400 Bad request`: - Request malformed. The bank replies with an `ErrorDetail` object. - :http:statuscode:`401 Unauthorized`: - Authentication failed, likely the credentials are wrong. - :http:statuscode:`404 Not found`: - * ``TALER_EC_BANK_UNKNOWN_ACCOUNT``: unknown account. - :http:statuscode:`501 Not Implemented`: - This server does not support account check. - - **Details:** - - .. ts:def:: AccountInfo - - interface AccountInfo { - } +.. include:: bank-wire/get-account-check.rst ----------------------- Wire Transfer Test APIs @@ -592,141 +87,15 @@ exposed by bank gateways in production. .. _twg-admin-add-incoming: -.. http:post:: /admin/add-incoming - - Simulate a transfer from a customer to the exchange. This API is *not* - idempotent since it's only used in testing. - - **Request:** - - .. ts:def:: AddIncomingRequest - - interface AddIncomingRequest { - // Amount to transfer. - amount: Amount; - - // Reserve public key that is included in the wire transfer details - // to identify the reserve that is being topped up. - reserve_pub: EddsaPublicKey; - - // Account (as full payto URI) that makes the wire transfer to the exchange. - // Usually this account must be created by the test harness before this - // API is used. An exception is the "fakebank", where any debit account - // can be specified, as it is automatically created. - debit_account: string; - } - - **Response:** - - :http:statuscode:`200 OK`: - The request has been correctly handled, so the funds have been transferred to - the recipient's account. The body is a `AddIncomingResponse`. - :http:statuscode:`400 Bad request`: - The request is malformed. The bank replies with an `ErrorDetail` object. - :http:statuscode:`401 Unauthorized`: - Authentication failed, likely the credentials are wrong. - :http:statuscode:`404 Not found`: - The endpoint is wrong or the user name is unknown. The bank replies with an `ErrorDetail` object. - :http:statuscode:`409 Conflict`: - The 'reserve_pub' argument was used previously in another transfer, and the specification mandates that reserve public keys must not be reused. - - **Details:** - - .. ts:def:: AddIncomingResponse - - interface AddIncomingResponse { - // Timestamp that indicates when the wire transfer will be executed. - // In cases where the wire transfer gateway is unable to know when - // the wire transfer will be executed, the time at which the request - // has been received and stored will be returned. - // The purpose of this field is for debugging (humans trying to find - // the transaction) as well as for taxation (determining which - // time period a transaction belongs to). - timestamp: Timestamp; - - // Opaque ID of the wire transfer initiation performed by the bank. - // It is different from the /history endpoints row_id. - row_id: SafeUint64; - } +.. include:: bank-wire/post-admin-add-incoming.rst .. _twg-admin-add-kycauth: -.. http:post:: /admin/add-kycauth - - Simulate a transfer from a customer to the exchange. This API is *not* - idempotent since it's only used in testing. - - **Request:** - - .. ts:def:: AddKycauthRequest - - interface AddKycauthRequest { - // Amount to transfer. - amount: Amount; - - // Account public key that is included in the wire transfer details - // to associate this key with the originating bank account. - account_pub: EddsaPublicKey; - - // Account (as full payto URI) that makes the wire transfer to the exchange. - // Usually this account must be created by the test harness before this - // API is used. An exception is the "fakebank", where any debit account - // can be specified, as it is automatically created. - debit_account: string; - } - - **Response:** - - :http:statuscode:`200 OK`: - The request has been correctly handled, so the funds have been transferred to - the recipient's account. The body is a `AddIncomingResponse`. - :http:statuscode:`400 Bad request`: - The request is malformed. The bank replies with an `ErrorDetail` object. - :http:statuscode:`401 Unauthorized`: - Authentication failed, likely the credentials are wrong. - :http:statuscode:`404 Not found`: - The endpoint is wrong or the user name is unknown. The bank replies with an `ErrorDetail` object. - -.. http:post:: /admin/add-mapped - - Simulate a transfer from a customer to the exchange. This API is *not* - idempotent since it's only used in testing. - - Since protocol **v5**. - - **Request:** - - .. ts:def:: AddMappedRequest - - interface AddMappedRequest { - // Amount to transfer. - amount: Amount; - - // Authorization public key used for registration. - authorization_pub: EddsaPublicKey; - - // Account (as full payto URI) that makes the wire transfer to the exchange. - // Usually this account must be created by the test harness before this - // API is used. An exception is the "fakebank", where any debit account - // can be specified, as it is automatically created. - debit_account: string; - } - - **Response:** +.. include:: bank-wire/post-admin-add-kycauth.rst - :http:statuscode:`200 OK`: - The request has been correctly handled, so the funds have been transferred to - the recipient's account. The body is a `AddIncomingResponse`. - :http:statuscode:`400 Bad request`: - The request is malformed. The bank replies with an `ErrorDetail` object. - :http:statuscode:`401 Unauthorized`: - Authentication failed, likely the credentials are wrong. - :http:statuscode:`404 Not found`: - The endpoint is wrong or the user name is unknown. The bank replies with an `ErrorDetail` object. - :http:statuscode:`409 Conflict`: - The 'authorization_pub' argument is unknown or have already been used for a non recurrent transfer. +.. include:: bank-wire/post-admin-add-mapped.rst Security Considerations diff --git a/core/api-challenger.rst b/core/api-challenger.rst @@ -114,55 +114,7 @@ The current protocol version is **v6**. Receiving Configuration ----------------------- -.. http:get:: /config - - Obtain the key configuration settings of the storage service. - - **Response:** - - :http:statuscode:`200 OK`: - Response is a `ChallengerConfigurationResponse`. - - .. ts:def:: ChallengerConfigurationResponse - - interface ChallengerConfigurationResponse { - // Name of the service - name: "challenger"; - - // libtool-style representation of the Challenger protocol version, see - // https://www.gnu.org/software/libtool/manual/html_node/Versioning.html#Versioning - // The format is "current:revision:age". - version: string; - - // URN of the implementation (needed to interpret 'revision' in version). - // @since v0, may become mandatory in the future. - implementation?: string; - - // @since **v2**. - // Object; map of keys (names of the fields of the address - // to be entered by the user) to objects with a "regex" (string) - // containing an extended Posix regular expression for allowed - // address field values, and a "hint"/"hint_i18n" giving a - // human-readable explanation to display if the value entered - // by the user does not match the regex. Keys that are not mapped - // to such an object have no restriction on the value provided by - // the user. See "ADDRESS_RESTRICTIONS" in the challenger configuration. - restrictions: Object; - - // @since **v6** - // Defines the set of fields asked to the user. - // The field names are registered via GANA at - // https://git.taler.net/gana.git/tree/gnu-taler-form-attributes - // email: CONTACT_EMAIL - // phone: CONTACT_PHONE - // postal: CONTACT_NAME, ADDRESS_LINES, ADDRESS_COUNTRY - // postal-ch: CONTACT_NAME, ADDRESS_LINES - address_type: "email" | "phone" | "postal" | "postal-ch"; - - // Hint to show in the address bar for the user as an example for - // the format of the address. - address_hint: string; - } +.. include:: challenger/get-config.rst .. _challenger-setup: @@ -170,68 +122,7 @@ Receiving Configuration Setup ----- -.. http:post:: /setup/$CLIENT_ID - - This endpoint is used by the client to authorize the execution of an address - validation on its behalf. An ``Authorization`` header (for now always using - a ``Bearer`` token) should be included to provide the client's credentials - to authorize access to the challenger service. This token must match the - ``client_secret`` from the registration of the client with the challenger - service (which will also be used in the later ``/token`` request). - - **Request:** - - The body can be an address in JSON encoding to pre-initialize the address to - be used by challenger for this process. If the body is absent, the user will - have to enter the full address details. The specific address format depends - on the address type. However, `ChallengeSetupRequest` defines the shared - ``read_only`` bit that has a special meaning independent of the address type: - it informs Challenger that the address should not be editable. - - Passing an address in the ``/setup`` body is supported @since protocol **v4**. - - **Response:** - - :http:statuscode:`200 OK`: - Response is a `ChallengeSetupResponse`. - :http:statuscode:`400 Bad request`: - The request is malformed. Usually returned with an - error code of ``TALER_EC_GENERIC_PARAMETER_MISSING`` or - ``TALER_EC_GENERIC_PARAMETER_MALFORMED``. - :http:statuscode:`404 Not found`: - The challenger service is unaware of a matching client. - or the credentials of the client are invalid. - Usually returned with - ``TALER_EC_CHALLENGER_GENERIC_CLIENT_UNKNOWN``. - :http:statuscode:`500 Internal server error`: - The challenger service encountered an internal error. - Usually returned with - ``TALER_EC_GENERIC_DB_FETCH_FAILED`` or - ``TALER_EC_GENERIC_DB_STORE_FAILED`` or - ``TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE``. - - **Details::** - - .. ts:def:: ChallengeSetupRequest - - interface ChallengeSetupRequest { - // If true, the given address should not be edited. - // Defaults to 'false' if not specified. - read_only?: boolean; - - // Optional, additional fields to pre-populate - // the address to be validated. - // The fields depend on the challenger type. - [x: string]: any; - } - - - .. ts:def:: ChallengeSetupResponse - - interface ChallengeSetupResponse { - // Nonce to use when constructing ``/authorize`` endpoint. - nonce: string; - } +.. include:: challenger/post-setup-CLIENT_ID.rst .. _challenger-login: @@ -240,91 +131,8 @@ Setup Login ----- -.. http:get:: /authorize/$NONCE -.. http:post:: /authorize/$NONCE - - This is the "authorization" endpoint of the OAuth 2.0 protocol. This - endpoint is used by the user-agent. It will return a form to enter the - address. - - The NONCE is a unique value identifying the challenge, should be shown to - the user so that they can recognize it when they receive the TAN code. - - Note that both for GET and POST requests the request arguments must - be given in the URL and the body should be empty. We currently do NOT - support using x-www-form-urlencoded arguments in the body, even for - a POST. - - **Request:** - - :query response_type: Must be ``code`` - :query client_id: Identifier of the client. - :query redirect_uri: URI-encoded redirection URI to use upon authorization. - :query state: Arbitrary client state to associate with the request. - :query scope: Not supported, any value is accepted. - :query code_challenge: A string to enhance security using PKCE (available since **v3**). - :query code_challenge_method: The method used for the code_challenge. Options are S256 (SHA-256) or plain (available since **v3**). - - **Response:** - - :http:statuscode:`200 OK`: - The the response is - a `ChallengeStatus`. Since protocol **v1**. - :http:statuscode:`302 Found`: - Returned when the client explicitly accepts ``text/html`` - returning a redirection to the WebUI. - Since protocol **v1**. - :http:statuscode:`400 Bad Request`: - The request does not follow the spec. - The response will include error - code, hint and detail. Since protocol **v1**. - :http:statuscode:`404 Not found`: - The service is unaware of a matching challenge. - The response will include error - code, hint and detail. Since protocol **v1**. - :http:statuscode:`406 Not Acceptable`: - The client ask for "text/html" and the backend installation does - not include the required HTML templates. - :http:statuscode:`500 Internal Server Error`: - Server is not able to respond due to internal problems. - The response will include error - code, hint and detail. Since protocol **v1**. - - .. ts:def:: ChallengeStatus - - interface ChallengeStatus { - - // indicates if the given address cannot be changed anymore, the - // form should be read-only if set to true. - fix_address: boolean; - - // form values from the previous submission if available, details depend - // on the ``ADDRESS_TYPE``, should be used to pre-populate the form - last_address?: Object; - - // is the challenge already solved? - solved: boolean; - - // number of times the address can still be changed, may or may not be - // shown to the user - changes_left: Integer; - - // when we would re-transmit the challenge the next - // time (at the earliest) if requested by the user - // only present if challenge already created - // @since **v2** - retransmission_time: Timestamp; - - // how many times might the PIN still be retransmitted - // only present if challenge already created - // @since **v2** - pin_transmissions_left?: Integer; - - // how many times might the user still try entering the PIN code - // only present if challenge already created - // @since **v2** - auth_attempts_left?: Integer; - } +.. include:: challenger/get-authorize-NONCE.rst +.. include:: challenger/post-authorize-NONCE.rst .. _challenger-challenge: @@ -333,99 +141,7 @@ Login Challenge --------- -.. http:post:: /challenge/$NONCE - - This endpoint is used by the user-agent to submit the address to which a - challenge should be sent by the challenger service. - - **Request:** - - Body should use the mime-type "application/x-www-form-urlencoded". - The posted form data must contain an object that follow the restrictions - defined in :ref:`config <challenger-config>`. - - **Response:** - - :http:statuscode:`200 OK`: - The response is `ChallengeResponse`. Since protocol **v2**. - :http:statuscode:`400 Bad Request`: - The request does not follow the spec. - The response will include error - code, hint and detail. Since protocol **v1**. - :http:statuscode:`403 Forbidden`: - The address being submitted differs from the previously - submitted address but the validation process was set up - as ``read_only`` and thus the address cannot be changed. - Returned with - ``TALER_EC_CHALLENGER_CLIENT_FORBIDDEN_READ_ONLY``. - Since protocol **v4**. - :http:statuscode:`404 Not Found`: - The service is unaware of a matching challenge. - The response will include error - code, hint and detail. Since protocol **v1**. - :http:statuscode:`406 Not Acceptable`: - The client ask for "text/html" and the backend installation does - not include the required HTML templates. - :http:statuscode:`429 Too Many Requests`: - There have been too many attempts to request challenge - transmissions for this $NONCE. The user-agent should - wait and (eventually) request a fresh nonce to be set - up by the client. - Returned with ``TALER_EC_CHALLENGER_TOO_MANY_ATTEMPTS``. - Since protocol **v2**. - :http:statuscode:`500 Internal Server Error`: - Server is not able to respond due to internal problems. - The response will include error - code, hint and detail. Since protocol **v1**. - :http:statuscode:`502 Bad Gateway`: - The challenger service failed to launch or communicate with - its helper process for delivering the challenge (SMS, e-mail, - postal mail). Returned with - ``TALER_EC_CHALLENGER_HELPER_EXEC_FAILED``. - - .. ts:def:: ChallengeResponse - - // Union discriminated by the "type" field. - type ChallengeResponse = ChallengeRedirect | ChallengeCreateResponse - - .. ts:def:: ChallengeRedirect - - // @since **v2** - interface ChallengeRedirect { - // Union discriminator field. - type: "completed"; - - // challenge is completed, use should redirect here - redirect_url: string; - } - - .. ts:def:: ChallengeCreateResponse - - interface ChallengeCreateResponse { - // Union discriminator field. - type: "created" - - // how many more attempts are allowed, might be shown to the user, - // highlighting might be appropriate for low values such as 1 or 2 (the - // form will never be used if the value is zero) - attempts_left: Integer; - - // the address that is being validated, might be shown or not - address: Object; - - // true if we just retransmitted the challenge, false if we sent a - // challenge recently and thus refused to transmit it again this time; - // might make a useful hint to the user - transmitted: boolean; - - // @deprecated in **v2**, use retransmission_time - next_tx_time?: string; - - // when we would re-transmit the challenge the next - // time (at the earliest) if requested by the user - // @since **v2** - retransmission_time: Timestamp; - } +.. include:: challenger/post-challenge-NONCE.rst .. _challenger-solve: @@ -434,90 +150,7 @@ Challenge Solve ----- -.. http:post:: /solve/$NONCE - - Used by the user-agent to submit an answer to the challenge. If the answer - is correct, the user will be redirected to the client's redirect URI, - otherwise the user may be given another chance to complete the process. - - **Request:** - - Body should use the mime-type "application/x-www-form-urlencoded". - The posted form data must contain a "pin" field. - - **Response:** - - :http:statuscode:`200 OK`: - If the request ask for application/json the response is - a `ChallengeSolveResponse`. Since protocol **v2**. - :http:statuscode:`302 Found`: - Only possible if request didn't ask for application/json. Since protocol **v2**. - The user is redirected to the redirect URI of the client to pass the - grant to the client. The target will be the redirect URI specified - by the client (during registration and again upon ``/authorize``), - plus a ``code`` argument with the authorization code, and the - ``state`` argument from the ``/authorize`` endpoint. - :http:statuscode:`400 Bad Request`: - The request does not follow the spec. - The response will include error - code, hint and detail. Since protocol **v1**. - :http:statuscode:`403 Forbidden`: - The response is `InvalidPinResponse`. Since protocol **v1**. - :http:statuscode:`404 Not found`: - The service is unaware of a matching challenge. - The response will include error - code, hint and detail. Since protocol **v1**. - :http:statuscode:`429 Too Many Requests`: - There have been too many attempts to solve the challenge - for this address (and $NONCE). The user-agent should - either try a different address (or wait and (eventually) - request a fresh nonce to be set up by the client). - The response will include error - code, hint and detail. Since protocol **v2**. - :http:statuscode:`500 Internal Server Error`: - Server is not able to respond due to internal problems. - The response will include error - code, hint and detail. Since protocol **v1**. - - .. ts:def:: ChallengeSolveResponse - - // Union discriminated by the "type" field. - type ChallengeSolveResponse = ChallengeRedirect | InvalidPinResponse; - - .. ts:def:: InvalidPinResponse - - interface InvalidPinResponse { - // Union discriminator field. - type: "pending"; - - // numeric Taler error code, should be shown to indicate the error - // compactly for reporting to developers - code: Integer; - - // human-readable Taler error code, should be shown for the user to - // understand the error - hint: string; - - // how many times is the user still allowed to change the address; - // if 0, the user should not be shown a link to jump to the - // address entry form - addresses_left: Integer; - - // how many times might the PIN still be retransmitted - pin_transmissions_left: Integer; - - // how many times might the user still try entering the PIN code - auth_attempts_left: Integer; - - // if true, the PIN was not even evaluated as the user previously - // exhausted the number of attempts - exhausted: boolean; - - // if true, the PIN was not even evaluated as no challenge was ever - // issued (the user must have skipped the step of providing their - // address first!) - no_challenge: boolean; - } +.. include:: challenger/post-solve-NONCE.rst .. _challenger-auth: @@ -525,82 +158,7 @@ Solve Auth ---- -.. http:post:: /token - - This is the token endpoint of the OAuth 2.0 specification. - This endpoint is used by the client to provide its authorization code, - demonstrating that it has the right to learn a particular user's validated - address. In return, the challenger service returns the access token. - Renewal is not supported. - - **Request:** - - The request must include an ``application/www-form-urlencoded`` body - specifying the ``client_id``, ``redirect_uri``, ``client_secret``, ``code`` - and ``grant_type``. The ``grant_type`` must be set to - ``authorization_code``. The ``redirect_uri`` must match the URI from - ``/authorize``. The ``code`` must be the authorization code that ``/solve`` - returned to the user. The ``client_id`` and ``client_secret`` must match - the usual client credentials. Since protocol **v3**, ``code_verifier`` can also be included. - - **Response:** - - Error responses follow RFC 6749, section 5.2 with an "error" field in JSON, - as well as also returning GNU Taler style error messages. - - :http:statuscode:`200 OK`: - The body will be a `ChallengerAuthResponse`. - :http:statuscode:`400 Bad Request`: - A required POST field (``grant_type``, ``client_id``, - ``client_secret``, ``code`` or ``redirect_uri``) is missing - or malformed, or ``grant_type`` is not ``authorization_code``. - Usually returned with ``TALER_EC_GENERIC_PARAMETER_MISSING`` - or ``TALER_EC_GENERIC_PARAMETER_MALFORMED``. - :http:statuscode:`401 Unauthorized`: - Authentication of the client failed. Returned (per - RFC 6749, section 5.2) when the client credentials are - invalid, when the supplied ``code`` is malformed or does - not match the validation, when the ``redirect_uri`` does - not match the one registered with the client, or when the - ``code_verifier`` does not match the saved - ``code_challenge``. Returned with - ``TALER_EC_CHALLENGER_GENERIC_CLIENT_FORBIDDEN_BAD_REDIRECT_URI``, - ``TALER_EC_CHALLENGER_CLIENT_FORBIDDEN_BAD_CODE``, - ``TALER_EC_CHALLENGER_GENERIC_VALIDATION_UNKNOWN`` or - ``TALER_EC_CHALLENGER_GRANT_UNKNOWN``. - PKCE-related rejections are since protocol **v3**. - :http:statuscode:`404 Not found`: - The service is unaware of a matching login process or client. - Returned with error codes of - ``TALER_EC_CHALLENGER_GENERIC_CLIENT_UNKOWN`` - :http:statuscode:`409 Conflict`: - A ``code`` was presented for a validation process for which - the user has not (yet) submitted any address, so the token - cannot be issued. Returned with - ``TALER_EC_CHALLENGER_MISSING_ADDRESS``. - :http:statuscode:`500 Internal Server Error`: - The challenger service encountered an internal error, - for example a database failure or a failure of the SHA-256 - or Base64 helpers used for PKCE verification. - Error codes used are: - * ``TALER_EC_CHALLENGER_GENERIC_DB_FETCH_FAILED`` - * ``TALER_EC_CHALLENGER_GENERIC_DB_STORE_FAILED`` - - **Details::** - - .. ts:def:: ChallengerAuthResponse - - interface ChallengerAuthResponse { - // Token used to authenticate access in ``/info``. - access_token: string; - - // Type of the access token. - token_type: "Bearer"; - - // Amount of time that an access token is valid (in seconds). - expires_in: Integer; - - } +.. include:: challenger/post-token.rst .. _challenger-info: @@ -609,50 +167,4 @@ Auth Info ---- -.. http:get:: /info - - This userinfo endpoint of the OAuth 2.0 specification. - This endpoint is used by the client to obtain the user's validated address. - - **Request:** - - Must include the token returned to the client from the ``/token`` endpoint - as a ``Bearer`` token in an ``Authorization`` header. - - **Response:** - - :http:statuscode:`200 OK`: - The body contains the address as a `ChallengerInfoResponse`. - :http:statuscode:`403 Forbidden`: - The bearer token is missing or invalid (malformed). - :http:statuscode:`404 Not found`: - The bearer token is invalid (includes unknown or expired). - Returned with ``TALER_EC_CHALLENGER_GRANT_UNKNOWN``. - :http:statuscode:`500 Internal Server Error`: - The challenger service encountered an internal error, - typically a database failure. Usually returned with - ``TALER_EC_GENERIC_DB_FETCH_FAILED``. - - **Details::** - - .. ts:def:: ChallengerInfoResponse - - interface ChallengerInfoResponse { - - // Unique ID of the record within Challenger - // (identifies the rowid of the token). - id: Integer; - - // Address that was validated. - // Key-value pairs, details depend on the - // address_type. - address: Object; - - // Type of the address. - address_type: string; - - // How long do we consider the address to be - // valid for this user. - expires: Timestamp; - - } +.. include:: challenger/get-info.rst diff --git a/core/api-corebank.rst b/core/api-corebank.rst @@ -55,88 +55,7 @@ The current protocol version is **v12**. Config ------ -.. http:get:: /config - - Return the protocol version and configuration information about the bank. - This specification corresponds to ``current`` protocol being version **v12**. - - **Response:** - - :http:statuscode:`200 OK`: - Response is a `Config`. - - **Details:** - - .. ts:def:: Config - - interface Config { - // Name of the API. - name: "taler-corebank"; - - // libtool-style representation of the Bank protocol version, see - // https://www.gnu.org/software/libtool/manual/html_node/Versioning.html#Versioning - // The format is "current:revision:age". - version: string; - - // Bank display name to be used in user interfaces. - // For consistency use "Taler Bank" if missing. - // @since **v4**, will become mandatory in the next version. - bank_name?: string; - - // Advertised base URL to use when you sharing an URL with another - // program. - // @since **v4**. - base_url?: string; - - // If 'true' the server provides local currency conversion support - // If 'false' some parts of the API are not supported and return 501 - allow_conversion: boolean; - - // If 'true' anyone can register - // If 'false' only admin can - allow_registrations: boolean; - - // If 'true' account can delete themselves - // If 'false' only admin can delete accounts - allow_deletions: boolean; - - // If 'true' anyone can edit their name - // If 'false' only admin can - allow_edit_name: boolean; - - // If 'true' anyone can edit their cashout account - // If 'false' only admin can - allow_edit_cashout_payto_uri: boolean; - - // Default debt limit for newly created accounts - default_debit_threshold: Amount; - - // Currency used by this bank. - currency: string; - - // How the bank SPA should render this currency. - currency_specification: CurrencySpecification; - - // TAN channels supported by the server - supported_tan_channels: TanChannel[]; - - // Wire transfer type supported by the bank. - // Defaults to 'iban' is missing - // @since **v4**, will become mandatory in the next version. - wire_type?: string; - - // Wire transfer execution fees. Only applies to bank transactions and withdrawals. - // @since **v4**, will become mandatory in the next version. - wire_transfer_fees?: Amount; - - // Minimum wire transfer amount allowed. Only applies to bank transactions and withdrawals. - // @since **v4**, will become mandatory in the next version. - min_wire_transfer_amount?: Amount; - - // Maximum wire transfer amount allowed. Only applies to bank transactions and withdrawals. - // @since **v4**, will become mandatory in the next version. - max_wire_transfer_amount?: Amount; - } +.. include:: corebank/get-config.rst @@ -152,157 +71,13 @@ The user ``admin`` is a special, hard-coded username. Some requests require the Since **v7** Basic authentication for endpoints other than ``/accounts/$USERNAME/token`` has been deprecated and will no longer be supported in the next release. -.. http:post:: /accounts/$USERNAME/token - - Create an authentification token. - - **Request:** - - .. ts:def:: TokenRequest - - interface TokenRequest { - // Scope for the token. - scope: "readonly" | "readwrite" | "revenue" | "wiregateway" | "observability"; - - // Custom token validity duration - duration?: RelativeTime; - - // Is the token refreshable into a new token during its - // validity? - // Refreshable tokens effectively provide indefinite - // access if they are refreshed in time. - refreshable?: boolean; - - // Optional token description - // @since **v4** - description?: string; - } - - **Response:** - - :http:statuscode:`200 Ok`: - Response is a `TokenSuccessResponse`. - :http:statuscode:`202 Accepted`: - 2FA is required for this operation. This returns the `ChallengeResponse` response. @since **v10** - :http:statuscode:`401 Unauthorized`: - Invalid or missing credentials. - :http:statuscode:`403 Forbidden`: - * ``TALER_EC_GENERIC_FORBIDDEN``: missing rights. - * ``TALER_EC_BANK_ACCOUNT_LOCKED``: account is locked and cannot create new token using its password. - - **Details:** - - .. ts:def:: TokenSuccessResponse - - interface TokenSuccessResponse { - // Expiration determined by the server. - // Can be based on the token_duration - // from the request, but ultimately the - // server decides the expiration. - expiration: Timestamp; - - // Opque access token. - access_token: string; - } +.. include:: corebank/post-accounts-USERNAME-token.rst -.. http:delete:: /accounts/$USERNAME/token +.. include:: corebank/delete-accounts-USERNAME-token.rst - Invalidate the access token that is being used to make the request. +.. include:: corebank/get-accounts-USERNAME-tokens.rst - **Authentication:** The client must authenticate with a valid access token. - - **Response:** - - :http:statuscode:`204 No content`: - The token have been deleted. - :http:statuscode:`401 Unauthorized`: - Invalid or missing credentials. - :http:statuscode:`403 Forbidden`: - Missing rights. - -.. http:get:: /accounts/$USERNAME/tokens - - Retrieve a subset of tokens related to $USERNAME. - @since **v4** - - **Request:** - - :query limit: *Optional.* - At most return the given number of results. Negative for descending by ``token_id``, positive for ascending by ``token_id``. Defaults to ``-20``. Since **v5**. - :query offset: *Optional.* - Starting ``token_id`` for :ref:`pagination <row-id-pagination>`. Since **v5**. - :query delta: *Optional.* - Deprecated since **v5**. Use *limit* instead. - :query start: *Optional.* - Deprecated since **v5**. Use *offset* instead. - - **Response:** - - :http:statuscode:`200 OK`: - Response is a `TokenInfos`. - :http:statuscode:`204 No content`: - No tokens. - :http:statuscode:`401 Unauthorized`: - Invalid or missing credentials. - :http:statuscode:`403 Forbidden`: - Mmissing rights. - - **Details:** - - .. ts:def:: TokenInfos - - interface TokenInfos { - tokens: TokenInfo[]; - } - - .. ts:def:: TokenInfo - - interface TokenInfo { - // Time when the token was created. - creation_time: Timestamp; - - // Expiration determined by the server. - // Can be based on the token_duration - // from the request, but ultimately the - // server decides the expiration. - expiration: Timestamp; - - // Scope for the token. - scope: "readonly" | "readwrite" | "revenue" | "wiregateway"; - - // Is the token refreshable into a new token during its - // validity? - // Refreshable tokens effectively provide indefinite - // access if they are refreshed in time. - refreshable: boolean; - - // Optional token description - description?: string; - - // Time when the token was last used. - last_access: Timestamp; - - // ID identifying the token - token_id: Integer; - - // deprecated since **v9**. Use *token_id* instead. - row_id: Integer; - } - -.. http:delete:: /accounts/$USERNAME/tokens/$TOKEN_ID - - Delete an access token. - - **Response:** - - :http:statuscode:`204 No content`: - The token have been deleted. - :http:statuscode:`404 Not found`: - Token ``$TOKEN_ID`` was not found. - :http:statuscode:`401 Unauthorized`: - Invalid or missing credentials. - :http:statuscode:`403 Forbidden`: - Missing rights. +.. include:: corebank/delete-accounts-USERNAME-tokens-TOKEN_ID.rst Bank Web UI ----------- @@ -315,1287 +90,81 @@ Account Management .. _bank-account-register: -.. http:post:: /accounts - - Create a new bank account. Depending on the configuration, - the account creation is self-serve, or only restricted to - the administrators. - - **Request:** - - .. ts:def:: RegisterAccountRequest - - interface RegisterAccountRequest { - // Username of the account - // Must match [a-zA-Z0-9-._~]{1, 126} - username: string; - - // Password of the account used for authentication - password: string; - - // Legal name of the account owner - name: string; - - // Make this account visible to anyone? - // Defaults to false. - is_public?: boolean; - - // Make this account a taler exchange account? - // If true: - // - incoming transactions to the account that do not - // have a valid reserve public key are automatically - // - the account provides the taler-wire-gateway-api endpoints - // Defaults to false. - is_taler_exchange?: boolean; - - // Addresses where to send the TAN for protected operations. - contact_data?: ChallengeContactData; - - // Payto URI of a fiat bank account. - // Payments will be sent to this bank account - // when the user wants to convert the regional currency - // back to fiat currency outside bank. - cashout_payto_uri?: string; - - // Simple payto URI of this bank account. - // Used mostly for testing, this field is ignored if the bank payment - // method is not IBAN. - payto_uri?: string; - - // If present, set the max debit allowed for this user - // Only admin can set this property. - debit_threshold?: Amount; - - // If present, set the user conversion rate class - // Only admin can set this property. - // @since **v9** - conversion_rate_class_id?: Integer; - - // @deprecated in **v10** - // If present, enables 2FA and set the TAN channel used for challenges - // Only admin can set this property, other user can reconfig their account - // after creation. - tan_channel?: TanChannel; - - // If present, enables 2FA and set the TAN channels used for challenges - // Only admin can set this property, other user can reconfig their account - // after creation. - // @since **v10** - tan_channels?: TanChannel[]; - - // @deprecated in **v9**, use conversion_rate_class_id instead - min_cashout?: Amount; - } - - .. ts:def:: ChallengeContactData - - interface ChallengeContactData { - // E-Mail address - email?: EmailAddress; - - // Phone number. - phone?: PhoneNumber; - } - - - **Response:** - - :http:statuscode:`200 OK`: - Response is a `RegisterAccountResponse`. - :http:statuscode:`400 Bad request`: - Input data was invalid. For example, the client specified a invalid - phone number or e-mail address. - :http:statuscode:`401 Unauthorized`: - Invalid or missing credentials. - :http:statuscode:`403 Forbidden`: - Missing rights. - :http:statuscode:`409 Conflict`: - * ``TALER_EC_BANK_REGISTER_USERNAME_REUSE`` : username already used. - * ``TALER_EC_BANK_REGISTER_PAYTO_URI_REUSE`` : payto URI already used. - * ``TALER_EC_BANK_UNALLOWED_DEBIT`` : admin account does not have sufficient funds to grant bonus. - * ``TALER_EC_BANK_RESERVED_USERNAME_CONFLICT`` : a reserved username was attempted, like ``admin`` or ``bank`` - * ``TALER_EC_BANK_NON_ADMIN_PATCH_DEBT_LIMIT`` : a non-admin user has tried to create an account with a customer debt limit. - * ``TALER_EC_BANK_NON_ADMIN_SET_CONVERSION_RATE_CLASS`` : a non-admin user has tried to create an account with a conversion rate class. Since **v9** - * ``TALER_EC_BANK_NON_ADMIN_SET_TAN_CHANNEL`` : a non-admin user has tried to create an account with 2fa. - * ``TALER_EC_BANK_TAN_CHANNEL_NOT_SUPPORTED``: ``tan_channel`` or one of ``tan_channels`` is not supported, check bank config to find supported ones. - * ``TALER_EC_BANK_MISSING_TAN_INFO``: the user did not share any contact data where to send the TAN via ``tan_channel`` or one of ``tan_channels``. - * ``TALER_EC_BANK_PASSWORD_TOO_SHORT``: password is shorter than 8 characters. - * ``TALER_EC_BANK_PASSWORD_TOO_LONG``: password is longer than 64 characters. - * ``TALER_EC_BANK_CONVERSION_RATE_CLASS_UNKNOWN`` : no conversion rate class found for this id. Since **v9** - - **Details:** - - .. ts:def:: RegisterAccountResponse - - interface RegisterAccountResponse { - // Full payto URI of this bank account. - internal_payto_uri: string; - } +.. include:: corebank/post-accounts.rst .. _account-reconfig: -.. http:patch:: /accounts/$USERNAME - - Allows reconfiguring the account data of ``$USERNAME``. - - **Request:** - - .. ts:def:: AccountReconfiguration - - interface AccountReconfiguration { - // Addresses where to send the TAN for protected operations. - contact_data?: ChallengeContactData; - - // Payto URI of a fiat bank account. - // Payments will be sent to this bank account - // when the user wants to convert the regional currency - // back to fiat currency outside bank. - // Only admin can change this property if not allowed in config - // Sending null will disable cashout - cashout_payto_uri?: string | null; - - // If present, change the legal name associated with $username. - // Only admin can change this property if not allowed in config - name?: string; - - // Make this account visible to anyone? - is_public?: boolean; - - // If present, change the max debit allowed for this user - // Only admin can change this property. - debit_threshold?: Amount; - - // If present, set the user conversion rate class - // Only admin can set this property. - // Sending null will remove the class and switch to default class - // @since **v9** - conversion_rate_class_id?: Integer | null; - - // @deprecated in **v10** - // If present, enables 2FA and set the TAN channel used for challenges - // Sending null will disable 2FA - tan_channel?: TanChannel | null; - - // If present and not empty, enables 2FA and set the TAN channels used for challenges - // Sending null or an empty array will disable 2FA - // @since **v10** - tan_channels?: TanChannel[] | null; - - // @deprecated in **v9**, user conversion rate classes instead - min_cashout?: Amount; - } - - **Response:** - - :http:statuscode:`202 Accepted`: - 2FA is required for this operation. This returns the `ChallengeResponse` response. @since **v10** - :http:statuscode:`204 No content`: - Operation successful. - :http:statuscode:`401 Unauthorized`: - Invalid or missing credentials. - :http:statuscode:`403 Forbidden`: - Missing rights. - :http:statuscode:`404 Not found`: - The account pointed by ``$USERNAME`` was not found. - :http:statuscode:`409 Conflict`: - * ``TALER_EC_BANK_NON_ADMIN_PATCH_LEGAL_NAME`` : a non-admin user has tried to change their legal name. - * ``TALER_EC_BANK_NON_ADMIN_PATCH_CASHOUT`` : a non-admin user has tried to change their cashout account. - * ``TALER_EC_BANK_NON_ADMIN_PATCH_DEBT_LIMIT`` : a non-admin user has tried to change their debt limit. - * ``TALER_EC_BANK_NON_ADMIN_SET_CONVERSION_RATE_CLASS`` : a non-admin user has tried to create an account with a conversion rate class. Since **v9** - * ``TALER_EC_BANK_TAN_CHANNEL_NOT_SUPPORTED`` : ``tan_channel`` or one of ``tan_channels`` is not supported, check bank config to find supported ones. - * ``TALER_EC_BANK_MISSING_TAN_INFO`` : the user did not share any contact data where to send the TAN via ``tan_channel`` or one of ``tan_channels``. - * ``TALER_EC_BANK_CONVERSION_RATE_CLASS_UNKNOWN`` : no conversion rate class found for this id. Since **v9** +.. include:: corebank/patch-accounts-USERNAME.rst .. _account-password-reconfig: -.. http:patch:: /accounts/$USERNAME/auth - - Allows changing the account's password. - - - **Request:** - - .. ts:def:: AccountPasswordChange - - interface AccountPasswordChange { - // Old password. If present it need to match the current - // password before updating. - old_password?: string; - // New password. - new_password: string; - } - - **Response:** - - :http:statuscode:`202 Accepted`: - 2FA is required for this operation. This returns the `ChallengeResponse` response. @since **v10** - :http:statuscode:`204 No content`: - Operation successful. - :http:statuscode:`404 Not found`: - The account pointed by ``$USERNAME`` was not found. - :http:statuscode:`401 Unauthorized`: - Invalid or missing credentials. - :http:statuscode:`403 Forbidden`: - Missing rights. - :http:statuscode:`409 Conflict`: - * ``TALER_EC_BANK_NON_ADMIN_PATCH_MISSING_OLD_PASSWORD``: a non-admin user has tried to change their password whihout providing the current one. - * ``TALER_EC_BANK_PATCH_BAD_OLD_PASSWORD`` : provided old password does not match current password. - * ``TALER_EC_BANK_PASSWORD_TOO_SHORT``: new password is shorter than 8 characters. - * ``TALER_EC_BANK_PASSWORD_TOO_LONG``: new password is longer than 64 characters. +.. include:: corebank/patch-accounts-USERNAME-auth.rst .. _delete-account: -.. http:delete:: /accounts/$USERNAME - - Delete the account whose username is ``$USERNAME``. The deletion - succeeds only if the balance is *zero*. Typically only available to - the administrator, but can be configured to allow ordinary users too. - - **Response:** - - :http:statuscode:`202 Accepted`: - 2FA is required for this operation. This returns the `ChallengeResponse` response. @since **v10** - :http:statuscode:`204 No content`: - The account was successfully deleted. - :http:statuscode:`401 Unauthorized`: - Invalid or missing credentials. - :http:statuscode:`403 Forbidden`: - Missing rights. - :http:statuscode:`404 Not found`: - The account pointed by ``$USERNAME`` was not found. - :http:statuscode:`409 Conflict`: - * ``TALER_EC_BANK_RESERVED_USERNAME_CONFLICT`` : a reserved username was attempted, like ``admin`` or ``bank``. - * ``TALER_EC_BANK_ACCOUNT_BALANCE_NOT_ZERO``: the account balance was not zero. +.. include:: corebank/delete-accounts-USERNAME.rst .. _account-list: -.. http:get:: /public-accounts - - Show those accounts whose histories are publicly visible. For example, - accounts from donation receivers. As such, this request is unauthenticated. +.. include:: corebank/get-public-accounts.rst - **Request:** - - :query limit: *Optional.* - At most return the given number of results. Negative for descending by ``row_id``, positive for ascending by ``row_id``. Defaults to ``-20``. Since **v5**. - :query offset: *Optional.* - Starting ``row_id`` for :ref:`pagination <row-id-pagination>`. Since **v5**. - :query filter_name: *Optional.* - Pattern to filter on the account's legal name. Given - the filter 'foo', all the results will **contain** - 'foo' in their legal name. Without this option, - all the existing accounts are returned. - :query delta: *Optional.* - Deprecated since **v5**. Use *limit* instead. - :query start: *Optional.* - Deprecated since **v5**. Use *offset* instead. - - **Response:** - - :http:statuscode:`200 OK`: - Response is a `PublicAccountsResponse`. - :http:statuscode:`204 No content`: - No public account. - - **Details:** - - .. ts:def:: PublicAccountsResponse - - interface PublicAccountsResponse { - public_accounts: PublicAccount[]; - } - - .. ts:def:: PublicAccount - - interface PublicAccount { - // Username of the account - username: string; - - // Full payto URI of this bank account. - payto_uri: string; - - // Current balance of the account - balance: Balance; - - // Is this a taler exchange account? - is_taler_exchange: boolean; - - // Opaque unique ID used for pagination. - // @since **v4**, will become mandatory in the next version. - row_id?: Integer; - } - -.. http:get:: /accounts - - Obtains a list of the accounts registered at the bank. - It returns only the information that this API handles, without - any balance or transactions list. - This request is only available to the administrator. - - **Request:** - - :query limit: *Optional.* - At most return the given number of results. Negative for descending by ``row_id``, positive for ascending by ``row_id``. Defaults to ``-20``. Since **v5**. - :query offset: *Optional.* - Starting ``row_id`` for :ref:`pagination <row-id-pagination>`. Since **v5**. - :query filter_name: *Optional.* - Pattern to filter on the account's legal name. Given - the filter 'foo', all the accounts will **contain** - 'foo' in their legal name. Without this option, - all the existing accounts are returned. - :query conversion_rate_class_id: *Optional.* - Id of a conversion rate class. Given the filter '1', the accounts will be part of the conversion rate class 1. Given the filter '0', will have no conversion rate class. Without this option all the existing accounts are returned. Since **v9**. - :query delta: *Optional.* - Deprecated since **v5**. Use *limit* instead. - :query start: *Optional.* - Deprecated since **v5**. Use *offset* instead. - - **Response:** - - :http:statuscode:`200 OK`: - At least one account was found. - The server responds with a `ListBankAccountsResponse` object. - :http:statuscode:`204 No Content`: - No accounts were found for the given request. - :http:statuscode:`401 Unauthorized`: - Invalid or missing credentials. - :http:statuscode:`403 Forbidden`: - Missing rights. - - **Details:** - - .. ts:def:: ListBankAccountsResponse - - interface ListBankAccountsResponse { - accounts: AccountMinimalData[]; - } - - .. ts:def:: Balance - - interface Balance { - amount: Amount; - credit_debit_indicator: "credit" | "debit"; - } - - .. ts:def:: AccountMinimalData - - interface AccountMinimalData { - // Username of the account - username: string; - - // Legal name of the account owner. - name: string; - - // Full payto URI of this bank account. - payto_uri: string; - - // Current balance of the account - balance: Balance; - - // Number indicating the max debit allowed for the requesting user. - debit_threshold: Amount; - - // Custom minimum cashout amount for this account. - // If null or absent, the global conversion fee is used. - // @since **v6** - // @deprecated in **v9**, use conversion_rate_class_id instead - min_cashout?: Amount; - - // Is this account visible to anyone? - is_public: boolean; - - // Is this a taler exchange account? - is_taler_exchange: boolean; - - // Is the account locked. - // Defaults to false. - // @deprecated since **v7** - is_locked?: boolean; - - // Opaque unique ID used for pagination. - // @since **v4**, will become mandatory in the next version. - row_id?: Integer; - - // Current status of the account - // active: the account can be used - // locked: the account can be used but cannot create new tokens - // @since **v7** - // deleted: the account has been deleted but is retained for compliance - // reasons, only the administrator can access it - // Defaults to 'active' is missing - // @since **v4**, will become mandatory in the next version. - status?: "active" | "locked" | "deleted"; - - // Conversion rate class of the user - // Only present if conversion is activated on the server - // @since **v9** - conversion_rate_class_id?: Integer; - - // Conversion rate available to the user - // Only present if conversion is activated on the server - // @since **v9** - conversion_rate?: ConversionRate; - } +.. include:: corebank/get-accounts.rst .. _bank-account-info: -.. http:get:: /accounts/$USERNAME - - Obtains information relative to the account owned by - ``$USERNAME``. The request is available to the administrator - and ``$USERNAME`` itself. - - **Response:** - - :http:statuscode:`200 OK`: - The bank responds with an `AccountData` object. - :http:statuscode:`401 Unauthorized`: - Invalid or missing credentials. - :http:statuscode:`403 Forbidden`: - Missing rights. - :http:statuscode:`404 Not found`: - The account pointed by ``$USERNAME`` was not found. - - **Details:** - - .. ts:def:: AccountData - - interface AccountData { - // Legal name of the account owner. - name: string; - - // Available balance on the account. - balance: Balance; - - // Full payto URI of the account. - payto_uri: string; - - // Number indicating the max debit allowed for the requesting user. - debit_threshold: Amount; - - // Custom minimum cashout amount for this account. - // If null or absent, the global conversion fee is used. - // @since **v6** - // @deprecated in **v9**, use conversion_rate_class_id instead - min_cashout?: Amount; - - // Addresses where to send the TAN for transactions. - // Currently only used for cashouts. - // If missing, cashouts will fail. - // In the future, might be used for other transactions - // as well. - contact_data?: ChallengeContactData; - - // Full 'payto' URI of a fiat bank account where to send cashouts with - // ``name`` as the 'receiver-name'. - // This field is optional - // because not all the accounts are required to participate - // in the merchants' circuit. One example is the exchange: - // that never cashouts. Registering these accounts can - // be done via the access API. - cashout_payto_uri?: string; - - // Is this account visible to anyone? - is_public: boolean; - - // Is this a taler exchange account? - is_taler_exchange: boolean; - - // Is the account locked. - // Defaults to false. - // @deprecated since **v7** - is_locked?: boolean; - - // @deprecated in **v10** - // Is 2FA enabled and what channel is used for challenges? - tan_channel?: TanChannel; - - // Is 2FA enabled and what channels are used for challenges? - // @since **v10** - tan_channels?: TanChannel[]; - - // Current status of the account - // active: the account can be used - // locked: the account can be used but cannot create new tokens - // @since **v7** - // deleted: the account has been deleted but is retained for compliance - // reasons, only the administrator can access it - // Defaults to 'active' is missing - // @since **v4**, will become mandatory in the next version. - status?: "active" | "locked" | "deleted"; - - // Conversion rate class of the user - // Only present if conversion is activated on the server - // @since **v9** - conversion_rate_class_id?: Integer; - } +.. include:: corebank/get-accounts-USERNAME.rst Transactions ------------ -.. http:get:: /accounts/$USERNAME/transactions - - Retrieve a subset of transactions related to $USERNAME. - - **Request:** - - :query limit: *Optional.* - At most return the given number of results. Negative for descending by ``row_id``, positive for ascending by ``row_id``. Defaults to ``-20``. Since **v5**. - :query offset: *Optional.* - Starting ``row_id`` for :ref:`pagination <row-id-pagination>`. Since **v5**. - :query timeout_ms: *Optional.* - Timeout in milliseconds, for :ref:`long-polling <long-polling>`, to wait for at least one element to be shown. Only useful if *limit* is positive. Since protocol **v5**. - :query delta: *Optional.* - Deprecated since **v5**. Use *limit* instead. - :query start: *Optional.* - Deprecated since **v5**. Use *offset* instead. - :query long_poll_ms: *Optional.* - Deprecated since **v5**. Use *timeout_ms* instead. - - **Response:** - - :http:statuscode:`200 OK`: - The bank responds with an `BankAccountTransactionsResponse` object. - :http:statuscode:`204 No content`: - No transaction found. - :http:statuscode:`401 Unauthorized`: - Invalid or missing credentials. - :http:statuscode:`403 Forbidden`: - Missing rights. - :http:statuscode:`404 Not found`: - The account pointed by ``$USERNAME`` was not found. - - **Details:** - - .. ts:def:: BankAccountTransactionsResponse - - interface BankAccountTransactionsResponse { - transactions: BankAccountTransactionInfo[]; - } - -.. http:get:: /accounts/$USERNAME/transactions/$TRANSACTION_ID - - Retrieve the transaction whose identifier is ``TRANSACTION_ID``. - - **Response:** - - :http:statuscode:`200 OK`: - The bank responds with an `BankAccountTransactionInfo` object. - :http:statuscode:`401 Unauthorized`: - Invalid or missing credentials. - :http:statuscode:`403 Forbidden`: - Missing rights. - :http:statuscode:`404 Not found`: - The account pointed by ``$USERNAME`` was not found. - - **Details:** - - .. ts:def:: BankAccountTransactionInfo - - interface BankAccountTransactionInfo { - // Full payto URI to identify the receiver of funds. - creditor_payto_uri: string; - - // Full payto URI to identify the sender of funds. - debtor_payto_uri: string; - - // Amount received. - amount: Amount; - - // The direction of the transaction relative to $USERNAME account. - // debit: $USERNAME is the debtor - // credit: $USERNAME is the creditor - direction: "debit" | "credit"; - - // The wire transfer subjec - subject: string; - - // Transaction unique ID. Matches - // $TRANSACTION_ID from the URI. - row_id: Integer; - - // Date of the transaction. - date: Timestamp; - } +.. include:: corebank/get-accounts-USERNAME-transactions.rst -.. http:post:: /accounts/$USERNAME/transactions +.. include:: corebank/get-accounts-USERNAME-transactions-TRANSACTION_ID.rst - Create a new transaction where the bank account with the label ``USERNAME`` is **debited**. - - **Request:** - - .. ts:def:: CreateTransactionRequest - - interface CreateTransactionRequest { - // Address in the payto format of the wire transfer receiver. - // It needs at least the 'message' query string parameter. - payto_uri: string; - - // Transaction amount (in the $currency:x.y format), optional. - // However, when not given, its value must occupy the 'amount' - // query string parameter of the 'payto' field. In case it - // is given in both places, the payto_uri's takes the precedence. - amount: string; - - // Nonce to make the request idempotent. Requests with the same - // ``request_uid`` that differ in any of the other fields - // are rejected. - // @since **v4**, will become mandatory in the next version. - request_uid?: ShortHashCode; - } - - **Response:** - - :http:statuscode:`200 Ok`: - The bank responds with an `CreateTransactionResponse` object. - :http:statuscode:`202 Accepted`: - 2FA is required for this operation. This returns the `ChallengeResponse` response. @since **v10** - :http:statuscode:`400 Bad Request`: - The request was invalid or the payto://-URI used unacceptable features. - :http:statuscode:`401 Unauthorized`: - Invalid or missing credentials. - :http:statuscode:`403 Forbidden`: - Missing rights. - :http:statuscode:`404 Not found`: - The account pointed by ``$USERNAME`` was not found. - :http:statuscode:`409 Conflict`: - * ``TALER_EC_BANK_SAME_ACCOUNT`` : creditor account is the same than ``USERNAME``. - * ``TALER_EC_BANK_UNKNOWN_CREDITOR`` : creditor account was not found. - * ``TALER_EC_BANK_UNALLOWED_DEBIT`` : the account does not have sufficient funds or the amount is too low or too high. - * ``TALER_EC_BANK_TRANSFER_REQUEST_UID_REUSED``: an operation with the same ``request_uid`` but different details has been submitted before. - - **Details:** - - .. ts:def:: CreateTransactionResponse - - interface CreateTransactionResponse { - // ID identifying the transaction being created - row_id: Integer; - } +.. include:: corebank/post-accounts-USERNAME-transactions.rst Account withdrawals ------------------- -.. http:post:: /accounts/$USERNAME/withdrawals - - Create a withdrawal operation, resulting in a ``taler://withdraw`` URI. - - **Request:** +.. include:: corebank/post-accounts-USERNAME-withdrawals.rst - The request must be a `BankAccountCreateWithdrawalRequest`. +.. include:: corebank/post-accounts-USERNAME-withdrawals-WITHDRAWAL_ID-confirm.rst - **Response:** +.. include:: corebank/post-accounts-USERNAME-withdrawals-WITHDRAWAL_ID-abort.rst - :http:statuscode:`200 Ok`: - The bank responds with an `BankAccountCreateWithdrawalResponse` object. - :http:statuscode:`401 Unauthorized`: - Invalid or missing credentials. - :http:statuscode:`403 Forbidden`: - Missing rights. - :http:statuscode:`404 Not found`: - The account pointed by ``$USERNAME`` was not found. - :http:statuscode:`409 Conflict`: - The account does not have sufficient funds. - - **Details:** - - .. ts:def:: BankAccountCreateWithdrawalRequest - - interface BankAccountCreateWithdrawalRequest { - // Amount to withdraw. If given, the wallet - // cannot change the amount. - // Optional since **v6**. - amount?: Amount; - - // Suggested amount to withdraw. The wallet can - // still change the suggestion. - // @since **v6** - suggested_amount?: Amount; - - // If true, tell the wallet not to allow the user to - // specify an amount to withdraw and to not provide - // any amount when registering with the withdrawal - // operation. The amount to withdraw will be set - // by the final ``/withdrawals/$WITHDRAWAL_ID/confirm`` step. - // @since **v8** - no_amount_to_wallet?: boolean; - } - - .. ts:def:: BankAccountCreateWithdrawalResponse - - interface BankAccountCreateWithdrawalResponse { - // ID identifying the operation being created - withdrawal_id: string; - - // URI that can be passed to the wallet to initiate the withdrawal - taler_withdraw_uri: string; - } - -.. http:post:: /accounts/$USERNAME/withdrawals/$WITHDRAWAL_ID/confirm - - Confirms ``WITHDRAWAL_ID`` operation. Has no effect on an already confirmed - withdrawal operation. This call is responsible for wiring the funds to the - exchange. - - **Request:** - - .. ts:def:: BankAccountConfirmWithdrawalRequest - - interface BankAccountConfirmWithdrawalRequest { - - // Selected amount to be transferred. Optional if the - // backend already knows the amount. - // @since **v6** - amount?: Amount; - } - - - **Response:** - - :http:statuscode:`202 Accepted`: - 2FA is required for this operation. This returns the `ChallengeResponse` response. @since **v10** - :http:statuscode:`204 No content`: - The withdrawal operation has been confirmed. - :http:statuscode:`401 Unauthorized`: - Invalid or missing credentials. - :http:statuscode:`403 Forbidden`: - Missing rights. - :http:statuscode:`404 Not found`: - The operation was not found. - :http:statuscode:`409 Conflict`: - * ``TALER_EC_BANK_CONFIRM_ABORT_CONFLICT`` : the withdrawal has been aborted previously and can't be confirmed. - * ``TALER_EC_BANK_CONFIRM_INCOMPLETE`` : the withdraw operation cannot be confirmed because no exchange and reserve public key selection happened before. - * ``TALER_EC_BANK_DUPLICATE_RESERVE_PUB_SUBJECT``: the reserve public key is already used. - * ``TALER_EC_BANK_UNALLOWED_DEBIT`` : the account does not have sufficient funds or the amount is too low or too high - * ``TALER_EC_BANK_AMOUNT_DIFFERS`` : the specified amount will not work for this withdrawal (since **v6**). - * ``TALER_EC_BANK_AMOUNT_REQUIRED`` : the backend requires an amount to be specified (since **v6**). - -.. http:post:: /accounts/$USERNAME/withdrawals/$WITHDRAWAL_ID/abort - - Aborts ``WITHDRAWAL_ID`` operation. Has no effect on an already aborted - operation. - - **Response:** - - :http:statuscode:`204 No content`: - The withdrawal operation has been aborted. - :http:statuscode:`401 Unauthorized`: - Invalid or missing credentials. - :http:statuscode:`403 Forbidden`: - Missing rights. - :http:statuscode:`404 Not found`: - The withdrawal operation was not found. - :http:statuscode:`409 Conflict`: - The withdrawal operation has been confirmed previously and can't be aborted. - -.. http:get:: /withdrawals/$WITHDRAWAL_ID - - Retrieve public information about ``WITHDRAWAL_ID`` withdrawal operation. - Does not require further authentication as knowledge of ``WITHDRAWAL_ID`` - serves as an authenticator. - - **Request:** - - :query old_state: - *Optional.* Defaults to "pending". - :query timeout_ms: *Optional.* - Timeout in milliseconds, for :ref:`long-polling <long-polling>`, to wait for the operation state to be different from *old_state*. Since **v5**. - :query long_poll_ms: *Optional.* - Deprecated since **v5.** Use *timeout_ms* instead. - - **Response:** - - :http:statuscode:`200 Ok`: - The bank responds with an `WithdrawalPublicInfo` object. - :http:statuscode:`404 Not found`: - The operation was not found. - - **Details:** - - .. ts:def:: WithdrawalPublicInfo - - interface WithdrawalPublicInfo { - // Current status of the operation - // pending: the operation is pending parameters selection (exchange and reserve public key) - // selected: the operations has been selected and is pending confirmation - // aborted: the operation has been aborted - // confirmed: the transfer has been confirmed and registered by the bank - status: "pending" | "selected" | "aborted" | "confirmed"; - - // Amount that will be withdrawn with this operation - // (raw amount without fee considerations). Only - // given once the amount is fixed and cannot be changed. - // Optional since **v6**. - amount?: Amount; - - // Suggestion for the amount to be withdrawn with this - // operation. Given if a suggestion was made but the - // user may still change the amount. - // Optional since **v6**. - suggested_amount?: Amount; - - // If true, the wallet must not allow the user to - // specify an amount to withdraw and to not provide - // any amount when registering with the withdrawal - // operation. The amount to withdraw will be set - // by the final ``/withdrawals/$WITHDRAWAL_ID/confirm`` step. - // @since **v8** - no_amount_to_wallet?: boolean; - - // Account username - username: string; - - // Reserve public key selected by the exchange, - // only non-null if ``status`` is ``selected`` or ``confirmed``. - selected_reserve_pub?: string; - - // Exchange account selected by the wallet - // only non-null if ``status`` is ``selected`` or ``confirmed``. - selected_exchange_account?: string; - } +.. include:: corebank/get-withdrawals-WITHDRAWAL_ID.rst Cashouts -------- .. _account-cashout: -.. http:post:: /accounts/$USERNAME/cashouts - - Initiates a conversion to fiat currency. The fiat - bank account to be - credited is the one specified at registration time via the - *cashout_payto_uri* parameter. The regional bank account - is specified via ``$USERNAME``. - - .. note:: - - Consult the `cashout rates call <cashout-rates>`_ to learn - about any applicable fee or exchange rate. - - - **Request:** - - .. ts:def:: CashoutRequest - - interface CashoutRequest { - // Nonce to make the request idempotent. Requests with the same - // ``request_uid`` that differ in any of the other fields - // are rejected. - request_uid: ShortHashCode; - - // Optional subject to associate to the - // cashout operation. This data will appear - // as the incoming wire transfer subject in - // the user's fiat bank account. - subject?: string; - - // That is the plain amount that the user specified - // to cashout. Its $currency is the (regional) currency of the - // bank instance. - amount_debit: Amount; - - // That is the amount that will effectively be - // transferred by the bank to the user's fiat bank - // account. - // It is expressed in the fiat currency and - // is calculated after the cashout fee and the - // exchange rate. See the /cashout-rate call. - // The client needs to calculate this amount - // correctly based on the amount_debit and the cashout rate, - // otherwise the request will fail. - amount_credit: Amount; - } - - **Response:** - - :http:statuscode:`200 OK`: - The cashout request was correctly created. - This returns the `CashoutResponse` response. - :http:statuscode:`202 Accepted`: - 2FA is required for this operation. This returns the `ChallengeResponse` response. @since **v10** - :http:statuscode:`401 Unauthorized`: - Invalid or missing credentials. - :http:statuscode:`403 Forbidden`: - Missing rights. - :http:statuscode:`404 Not found`: - The account pointed by ``$USERNAME`` was not found. - :http:statuscode:`409 Conflict`: - * ``TALER_EC_BANK_TRANSFER_REQUEST_UID_REUSED``: an operation with the same ``request_uid`` but different details has been submitted before. - * ``TALER_EC_BANK_BAD_CONVERSION``: exchange rate was calculated incorrectly by the client. - * ``TALER_EC_BANK_BANK_CONVERSION_AMOUNT_TO_SMALL``: the amount of the cashout is too small. - * ``TALER_EC_BANK_UNALLOWED_DEBIT``: the account does not have sufficient funds or the amount is too low or too high. - * ``TALER_EC_BANK_CONFIRM_INCOMPLETE``: the user did not share any cashout payto to uri where to wire funds. - :http:statuscode:`501 Not Implemented`: - * ``TALER_EC_BANK_TAN_CHANNEL_NOT_SUPPORTED``: the chosen ``tan_channel`` or one of ``tan_channels`` is not currently supported. - * This server does not support conversion, client should check config response. - - **Details:** - - .. ts:def:: CashoutResponse - - interface CashoutResponse { - // ID identifying the operation being created - cashout_id: Integer; - } +.. include:: corebank/post-accounts-USERNAME-cashouts.rst .. _circuit-cashout-details: -.. http:get:: /accounts/$USERNAME/cashouts/$CASHOUT_ID - - Returns information about the status of the ``$CASHOUT_ID`` operation. - The request is available to the administrator and the account owner. - - **Response:** - - :http:statuscode:`200 OK`: - Response is a `CashoutStatusResponse`. - :http:statuscode:`401 Unauthorized`: - Invalid or missing credentials. - :http:statuscode:`403 Forbidden`: - Missing rights. - :http:statuscode:`404 Not found`: - The cashout operation was not found. - :http:statuscode:`501 Not implemented`: - This server does not support conversion, client should check config response. - - **Details:** - - .. ts:def:: CashoutStatusResponse - - interface CashoutStatusResponse { - // Amount debited to the regional bank account. - amount_debit: Amount; - - // Amount credited to the fiat bank account. - amount_credit: Amount; - - // Transaction subject. - subject: string; - - // Time when the cashout was created. - creation_time: Timestamp; - } +.. include:: corebank/get-accounts-USERNAME-cashouts-CASHOUT_ID.rst .. _circuit-cashouts: -.. http:get:: /accounts/$USERNAME/cashouts - - Returns the list of all cash-out operations for an account. - - **Request:** - - :query limit: *Optional.* - At most return the given number of results. Negative for descending by ``cashout_id``, positive for ascending by ``cashout_id``. Defaults to ``-20``. Since **v5**. - :query offset: *Optional.* - Starting ``cashout_id`` for :ref:`pagination <row-id-pagination>`. Since **v5**. - :query delta: *Optional.* - Deprecated since **v5**. Use *limit* instead. - :query start: *Optional.* - Deprecated since **v5**. Use *offset* instead. - - **Response:** - - :http:statuscode:`200 OK`: - Response is a `Cashouts`. - :http:statuscode:`204 No Content`: - No cash-out operations were found. - :http:statuscode:`401 Unauthorized`: - Invalid or missing credentials. - :http:statuscode:`403 Forbidden`: - Missing rights. - :http:statuscode:`501 Not implemented`: - This server does not support conversion, client should check config response. - - **Details:** - - .. ts:def:: Cashouts - - interface Cashouts { - // Every string represents a cash-out operation ID. - cashouts: CashoutInfo[]; - } - - .. ts:def:: CashoutInfo - - interface CashoutInfo { - cashout_id: Integer; - } +.. include:: corebank/get-accounts-USERNAME-cashouts.rst -.. http:get:: /cashouts - - Returns the list of all cash-out operations for **all** accounts. - - Can only be used by the administrators. - - **Request:** - - :query limit: *Optional.* - At most return the given number of results. Negative for descending by ``cashout_id``, positive for ascending by ``cashout_id``. Defaults to ``-20``. Since **v5**. - :query offset: *Optional.* - Starting ``cashout_id`` for :ref:`pagination <row-id-pagination>`. Since **v5**. - :query delta: *Optional.* - Deprecated since **v5**. Use *limit* instead. - :query start: *Optional.* - Deprecated since **v5**. Use *offset* instead. - - .. note:: - - We might want to add a filter in the future to only - query pending cashout operations. - - **Response:** - - :http:statuscode:`200 OK`: - Response is a `GlobalCashouts`. - :http:statuscode:`204 No Content`: - No cash-out operations were found. - :http:statuscode:`401 Unauthorized`: - Invalid or missing credentials. - :http:statuscode:`403 Forbidden`: - Missing rights. - :http:statuscode:`501 Not implemented`: - This server does not support conversion, client should check config response. - - **Details:** - - .. ts:def:: GlobalCashouts - - interface GlobalCashouts { - cashouts: GlobalCashoutInfo[]; - } - - .. ts:def:: GlobalCashoutInfo - - interface GlobalCashoutInfo { - cashout_id: Integer; - username: string; - } +.. include:: corebank/get-cashouts.rst Conversion rate class --------------------- -.. http:post:: /conversion-rate-classes - - Create a new conversion rate classe. - - Only available to the administrator. - - Since protocol **v9**. - - **Request:** - - .. ts:def:: ConversionRateClassInput - - interface ConversionRateClassInput { - // The name of this class - name: string; - - // A description of the class - description?: string; - - // Minimum fiat amount authorised for cashin before conversion - cashin_min_amount?: Amount; - - // Exchange rate to buy regional currency from fiat - cashin_ratio?: DecimalNumber; - - // Regional amount fee to subtract after applying the cashin ratio. - cashin_fee?: Amount; - - // Rounding mode used during cashin conversion - cashin_rounding_mode?: "zero" | "up" | "nearest"; - - // Minimum regional amount authorised for cashout before conversion - cashout_min_amount?: Amount; - - // Exchange rate to sell regional currency for fiat - cashout_ratio?: DecimalNumber; - - // Fiat amount fee to subtract after applying the cashout ratio. - cashout_fee?: Amount; - - // Rounding mode used during cashout conversion - cashout_rounding_mode?: "zero" | "up" | "nearest"; - } - - **Response:** - - :http:statuscode:`200 OK`: - The conversion rate class request was correctly created. - This returns the `ConversionRateClassResponse` response. - :http:statuscode:`401 Unauthorized`: - Invalid or missing credentials. - :http:statuscode:`403 Forbidden`: - Missing rights. - :http:statuscode:`409 Conflict`: - * ``TALER_EC_BANK_NAME_REUSE`` : name already used. - :http:statuscode:`501 Not implemented`: - This server does not support conversion, client should check config response. - - **Details:** - - .. ts:def:: ConversionRateClassResponse - - interface ConversionRateClassResponse { - // ID identifying the conversion rate class being created - conversion_rate_class_id: Integer; - } - -.. http:patch:: /conversion-rate-classes/{CLASS_ID} - - Edit an existing conversion rate class. - - Only available to the administrator. - - Since protocol **v9**. - - **Request:** - - `ConversionRateClassInput` - - **Response:** - - :http:statuscode:`204 No Content`: - The conversion rate class request was correctly edited. - :http:statuscode:`401 Unauthorized`: - Invalid or missing credentials. - :http:statuscode:`403 Forbidden`: - Missing rights. - :http:statuscode:`404 Not Found`: - The conversion rate class was not found. - :http:statuscode:`409 Conflict`: - * ``TALER_EC_BANK_NAME_REUSE`` : name already used. - :http:statuscode:`501 Not implemented`: - This server does not support conversion, client should check config response. - -.. http:delete:: /conversion-rate-classes/{CLASS_ID} - - Delete an existing conversion rate class. - - Only available to the administrator. - - Since protocol **v9**. - - **Response:** - - :http:statuscode:`204 No Content`: - The conversion rate class request was correctly deleted. - :http:statuscode:`401 Unauthorized`: - Invalid or missing credentials. - :http:statuscode:`403 Forbidden`: - Missing rights. - :http:statuscode:`404 Not Found`: - The conversion rate class was not found. - :http:statuscode:`409 Conflict`: - * ``TODO_LINKED_ACCOUNT`` : some accounts belongs to this class. - :http:statuscode:`501 Not implemented`: - This server does not support conversion, client should check config response. - -.. http:get:: /conversion-rate-classes/{CLASS_ID} - - Get an existing conversion rate class. - - Only available to the administrator. - - Since protocol **v9**. - - **Response:** - - :http:statuscode:`200 OK`: - Response is a `ConversionRateClass`. - :http:statuscode:`401 Unauthorized`: - Invalid or missing credentials. - :http:statuscode:`403 Forbidden`: - Missing rights. - :http:statuscode:`404 Not Found`: - The conversion rate class was not found. - :http:statuscode:`501 Not implemented`: - This server does not support conversion, client should check config response. - - **Details:** - - .. ts:def:: ConversionRateClassResponse - - interface ConversionRateClass { - // The name of this class - name: string; - - // A description of the class - description?: string; - - // Class unique ID - conversion_rate_class_id: Integer; - - // Number of users affected to this class - num_users: Integer; - - // Minimum fiat amount authorised for cashin before conversion - cashin_min_amount?: Amount; - - // Exchange rate to buy regional currency from fiat - cashin_ratio?: DecimalNumber; - - // Regional amount fee to subtract after applying the cashin ratio. - cashin_fee?: Amount; - - // Rounding mode used during cashin conversion - cashin_rounding_mode?: "zero" | "up" | "nearest"; - - // Minimum regional amount authorised for cashout before conversion - cashout_min_amount?: Amount; - - // Exchange rate to sell regional currency for fiat - cashout_ratio?: DecimalNumber; - - // Fiat amount fee to subtract after applying the cashout ratio. - cashout_fee?: Amount; - - // Rounding mode used during cashout conversion - cashout_rounding_mode?: "zero" | "up" | "nearest"; - } - -.. http:get:: /conversion-rate-classes - - Returns the list of all conversion rate classes. - - Only available to the administrator. +.. include:: corebank/post-conversion-rate-classes.rst - Since protocol **v9**. +.. include:: corebank/patch-conversion-rate-classes-CLASS_ID.rst - **Request:** +.. include:: corebank/delete-conversion-rate-classes-CLASS_ID.rst - :query limit: *Optional.* - At most return the given number of results. Negative for descending by ``conversion_rate_class_id``, positive for ascending by ``conversion_rate_class_id``. Defaults to ``-20``. - :query offset: *Optional.* - Starting ``conversion_rate_class_id`` for :ref:`pagination <row-id-pagination>`. - :query filter_name: *Optional.* - Pattern to filter on the class name. Given - the filter 'foo', all the classes will **contain** - 'foo' in their name. Without this option, - all the existing classes are returned. +.. include:: corebank/get-conversion-rate-classes-CLASS_ID.rst - **Response:** - - :http:statuscode:`200 OK`: - Response is a `ConversionRateClasses`. - :http:statuscode:`401 Unauthorized`: - Invalid or missing credentials. - :http:statuscode:`403 Forbidden`: - Missing rights. - :http:statuscode:`404 Not Found`: - The conversion rate class was not found. - :http:statuscode:`501 Not implemented`: - This server does not support conversion, client should check config response. - - **Details:** - - .. ts:def:: ConversionRateClasses - - interface ConversionRateClasses { - classes: ConversionRateClass[]; - } +.. include:: corebank/get-conversion-rate-classes.rst Two Factor Auth @@ -1659,268 +228,36 @@ remain absolutely unchanged. Requesting challenges ^^^^^^^^^^^^^^^^^^^^^ -.. http:post:: /accounts/$USERNAME/challenge/$CHALLENGE_ID - - Send TAN code for the ``CHALLENGE_ID`` challenge. - - This request can be posted several times to trigger TAN retransmission when the current code has expired or too many confirmation attempts have been made. - - This endpoint is not authenticated. @since **v10** - - **Request:** - - The request body must be empty. - - **Response:** - - :http:statuscode:`200 Ok`: - The TAN code has been sent. The body will be a `ChallengeRequestResponse`. - :http:statuscode:`404 Not Found`: - * ``TALER_EC_BANK_TAN_CHANNEL_SCRIPT_FAILED``: TAN transmition failed. - * ``TALER_EC_BANK_TAN_CHALLENGE_EXPIRED``: TAN transmition failed. - The challenge was not found. - :http:statuscode:`410 Gone`: - The challenge was already solved. - :http:statuscode:`429 Too many requests`: - Too many challenges are active right now, you must wait or confirm current challenges. - :http:statuscode:`502 Bad Gateway`: - * ``TALER_EC_BANK_TAN_CHANNEL_SCRIPT_FAILED``: TAN transmition failed. - - **Details:** - - .. ts:def:: ChallengeRequestResponse - - interface ChallengeRequestResponse { - // How long does the client have to solve the - // challenge. - solve_expiration: Timestamp; - - // What is the earlist time at which the client - // may request a new challenge to be transmitted? - earliest_retransmission: Timestamp; - } +.. include:: corebank/post-accounts-USERNAME-challenge-CHALLENGE_ID.rst Solving challenges ^^^^^^^^^^^^^^^^^^ -.. http:post:: /accounts/$USERNAME/challenge/$CHALLENGE_ID/confirm - - Solves the ``CHALLENGE_ID`` challenge and allows performing the protected operation. - - When the challenge is confirmed, you can call the protected endpoint again with ``CHALLENGE_ID`` in the ``Taler-Challenge-Ids`` HTTP header and an the original request body. - - This endpoints is not authenticated. Too many unsuccessful attempts to confirm token creation challenges block the account. - - **Request:** - - .. ts:def:: ChallengeSolve - - interface ChallengeSolve { - // The TAN code that solves $CHALLENGE_ID - tan: string; - } - - **Response:** - - :http:statuscode:`204 No Content`: - The challenge is confirmed. - :http:statuscode:`404 Not Found`: - * ``TALER_EC_BANK_TRANSACTION_NOT_FOUND`` : unknown challenge TAN. - * ``TALER_EC_BANK_TAN_CHALLENGE_EXPIRED`` : expired challenge. - :http:statuscode:`409 Conflict`: - * ``TALER_EC_BANK_TAN_CHALLENGE_FAILED`` : wrong TAN. - * ``TALER_EC_BANK_TAN_CHALLENGE_EXPIRED`` : expired TAN. - :http:statuscode:`429 Too many requests`: - Too many failed confirmation attempts, a new TAN must be requested. +.. include:: corebank/post-accounts-USERNAME-challenge-CHALLENGE_ID-confirm.rst Monitor ------- -.. http:get:: /monitor - - When the bank provides conversion between the local currency and an - external one, this call lets the bank administrator monitor the cashin - and cashout operations that were made from and to the external currency. - It shows as well figures related to internal payments made by a Taler - exchange component to internal bank accounts. Timeframes are in UTC. - - **Request:** - - :query timeframe: *Optional*. - This parameter admits one of the following values. Defaults to 'hour'. - - * hour - * day - * month - * year - - :query date_s: *Optional*. - Non-negative date in seconds after the UNIX Epoch. Defaults to current time. - @since **v4** - - :query which: *Optional*. - This parameter points at a particular element of the *timeframe* parameter. - Following are the admitted values for each one. - Defaults to the last snapshot taken of the *timeframe* parameter. - @deprecated since **v4** - - * hour: from 00 to 23 - * day: from 1 to the last day of the current month. - * month: from 1 to 12 - * year: Gregorian year in the YYYY format. - - **Response:** - - :http:statuscode:`200 OK`: - The bank responds with `MonitorResponse`. - :http:statuscode:`400 Bad Request`: - This error may indicate that the *which* parameter is not appropriate for the selected *timeframe*. For example, timeframe=month and which=20 would result in this error. - :http:statuscode:`401 Unauthorized`: - Invalid or missing credentials. - :http:statuscode:`403 Forbidden`: - Missing rights. - - **Details:** - - .. note:: - - API consumers may combine the values in the response with other - factors to serve different views to their users. - - .. ts:def:: MonitorResponse - - // Union discriminated by the "type" field. - type MonitorResponse = - | MonitorNoConversion - | MonitorWithConversion; - - .. ts:def:: MonitorNoConversion - - // Monitoring stats when conversion is not supported - interface MonitorNoConversion { - type: "no-conversions"; - - // How many payments were made to a Taler exchange by another - // bank account. - talerInCount: Integer; - - // Overall volume that has been paid to a Taler - // exchange by another bank account. - talerInVolume: Amount; - - // How many payments were made by a Taler exchange to another - // bank account. - talerOutCount: Integer; - - // Overall volume that has been paid by a Taler - // exchange to another bank account. - talerOutVolume: Amount; - } - - .. ts:def:: MonitorWithConversion - - // Monitoring stats when conversion is supported - interface MonitorWithConversion { - type: "with-conversions"; - - // How many cashin operations were confirmed by a - // wallet owner. Note: wallet owners - // are NOT required to be customers of the libeufin-bank. - cashinCount: Integer; - - // Overall regional currency that has been paid by the regional admin account - // to regional bank accounts to fulfill all the confirmed cashin operations. - cashinRegionalVolume: Amount; - - // Overall fiat currency that has been paid to the fiat admin account - // by fiat bank accounts to fulfill all the confirmed cashin operations. - cashinFiatVolume: Amount; - - // How many cashout operations were confirmed. - cashoutCount: Integer; - - // Overall regional currency that has been paid to the regional admin account - // by fiat bank accounts to fulfill all the confirmed cashout operations. - cashoutRegionalVolume: Amount; - - // Overall fiat currency that has been paid by the fiat admin account - // to fiat bank accounts to fulfill all the confirmed cashout operations. - cashoutFiatVolume: Amount; - - // How many payments were made to a Taler exchange by another - // bank account. - talerInCount: Integer; - - // Overall volume that has been paid to a Taler - // exchange by another bank account. - talerInVolume: Amount; - - // How many payments were made by a Taler exchange to another - // bank account. - talerOutCount: Integer; - - // Overall volume that has been paid by a Taler - // exchange to another bank account. - talerOutVolume: Amount; - } +.. include:: corebank/get-monitor.rst Endpoints for Integrated Sub-APIs --------------------------------- -.. http:any:: /taler-integration/* - - All endpoints under this prefix are specified by the. - :doc:`GNU Taler bank integration API </core/api-bank-integration>`. - This API handles the communication with Taler wallets. - - -.. http:any:: /accounts/$USERNAME/taler-wire-gateway/* - - All endpoints under this prefix are specified - by the :doc:`GNU Taler wire gateway API </core/api-bank-wire>`. - - The endpoints are only available for accounts configured with ``is_taler_exchange=true``. - -.. http:any:: /accounts/$USERNAME/taler-wire-transfer-gateway/* - - Since **v12** - - All endpoints under this prefix are specified - by the :doc:`GNU Taler prepared transfer API </core/api-bank-transfer>`. - - The endpoints are only available for accounts configured with ``is_taler_exchange=true``. - -.. http:any:: /accounts/$USERNAME/taler-revenue/* - - All endpoints under this prefix are specified - by the :doc:`GNU Taler Revenue API </core/api-bank-revenue>`. - -.. http:any:: /accounts/$USERNAME/conversion-info/* - - User custom rates, public for accounts configured with ``is_taler_exchange=true`` else private. Since **v9** - - All endpoints under this prefix are specified - by the :doc:`GNU Taler Conversion Info API </core/api-bank-conversion-info>`. - -.. http:any:: /conversion-rate-classes/$CLASS_ID/conversion-info/* +.. include:: corebank/any-taler-integration-star.rst - Conversion rate conversion infos, admin only. Since **v9** - All endpoints under this prefix are specified - by the :doc:`GNU Taler Conversion Info API </core/api-bank-conversion-info>`. +.. include:: corebank/any-accounts-USERNAME-taler-wire-gateway-star.rst -.. http:any:: /conversion-info/* +.. include:: corebank/any-accounts-USERNAME-taler-wire-transfer-gateway-star.rst - Global conversion rate infos. +.. include:: corebank/any-accounts-USERNAME-taler-revenue-star.rst - All endpoints under this prefix are specified - by the :doc:`GNU Taler Conversion Info API </core/api-bank-conversion-info>`. +.. include:: corebank/any-accounts-USERNAME-conversion-info-star.rst -.. http:any:: /taler-observability/* +.. include:: corebank/any-conversion-rate-classes-CLASS_ID-conversion-info-star.rst - Since **v11** +.. include:: corebank/any-conversion-info-star.rst - All endpoints under this prefix are specified - by the :doc:`GNU Taler Observability API </core/api-observability>`. +.. include:: corebank/any-taler-observability-star.rst diff --git a/core/api-ebisync.rst b/core/api-ebisync.rst @@ -51,35 +51,7 @@ LibEuFin EbiSync API. Config ------ -.. http:get:: /config - - Return the protocol version and configuration information about the bank. - This specification corresponds to ``current`` protocol being version **v0**. - - **Response:** - - :http:statuscode:`200 OK`: - Response is a `Config`. - - **Details:** - - .. ts:def:: Config - - interface Config { - // Name of the API. - name: "taler-ebisync"; - - // libtool-style representation of the Bank protocol version, see - // https://www.gnu.org/software/libtool/manual/html_node/Versioning.html#Versioning - // The format is "current:revision:age". - version: string; - - // URN of the implementation (needed to interpret 'revision' in version). - implementation: string; - - // SPA display version to be used in user interfaces. - spa_version: string; - } +.. include:: ebisync/get-config.rst Web UI ------ @@ -89,66 +61,6 @@ The web UI served under ``/``. Submit ------ -.. http:get:: /submit - - Obtains a list of the orders that can be used. - - **Response:** - - :http:statuscode:`200 OK`: - The server responds with a `ListSubmitOrders` object. - :http:statuscode:`401 Unauthorized`: - Invalid or missing credentials. - :http:statuscode:`403 Forbidden`: - Missing rights. - - **Details:** - - .. ts:def:: ListSubmitOrders - - interface ListSubmitOrders { - orders: SubmitOrder[]; - } - - .. ts:def:: SubmitOrder - - interface SubmitOrder { - // EBICS order id to uniquely identify this order - id: string; - - // EBICS order description provided by the EBICS server - description: string; - } - -.. http:post:: /submit - - Submit an file to the EBICS server using a chosen order. - - **Request:** - - :formparam file: The file to submit. - :formparam order: The is of the EBICS order to use. - - **Response:** - - :http:statuscode:`200 OK`: - Response is a `SubmitResponse`. - :http:statuscode:`400 Bad request`: - Input data was invalid. - :http:statuscode:`401 Unauthorized`: - Invalid or missing credentials. - :http:statuscode:`403 Forbidden`: - Missing rights. - :http:statuscode:`409 Conflict`: - EBICS server validation error. - :http:statuscode:`502 Bad Gateway`: - EBICS server connection error. - - **Details:** - - .. ts:def:: SubmitResponse +.. include:: ebisync/get-submit.rst - interface SubmitResponse { - // EBICS upload order ID - order: string; - } +.. include:: ebisync/post-submit.rst diff --git a/core/api-mailbox.rst b/core/api-mailbox.rst @@ -65,327 +65,27 @@ The current protocol version is **v0**. Configuration information ------------------------- -.. http:get:: /config - - Return the protocol version and currency supported by this service. - - **Response:** - - :http:statuscode:`200 OK`: - The body is a `VersionResponse`. - - **Details:** - - .. ts:def:: VersionResponse - - interface VersionResponse { - // libtool-style representation of the Merchant protocol version, see - // https://www.gnu.org/software/libtool/manual/html_node/Versioning.html#Versioning - // The format is "current:revision:age". - version: string; - - // Name of the protocol. - name: "taler-mailbox"; - - // Fee per message. - message_fee: Amount; - - // Fixed size of message body. - message_body_bytes: Integer; - - // Maximum number of messages in a - // single response. - message_response_limit: Integer; - - // How long will the service store a message - // before giving up on delivery? - delivery_period: RelativeTime; - - // How much is the cost of a single - // registration (update) of a mailbox - // May be 0 for a free update/registration. - registration_update_fee: Amount - - // How much is the cost of a single - // registration period (30 days) of a mailbox - // May be 0 for a free registration. - monthly_fee: Amount - - // How much is the cost to send a single - // message to a mailbox. - // May be 0 for free message sending. - message_fee: Amount - - // How many messages can be send and - // are stored by the service for free. - // After the quota is reached, the - // regular message_fee applies. - // May be 0 for no free quota. - free_message_quota: Integer - - } +.. include:: mailbox/get-config.rst --------------------------------- Mailbox registration and metadata --------------------------------- -.. http:get:: /info/$H_MAILBOX - - Endpoint that returns mailbox metadata including signing and encryption keys for ``$H_MAILBOX``. - - **Response** - - :http:statuscode:`200 Ok`: - Info is returned in a `MailboxMetadata` response, - :http:statuscode:`404 Not Found`: - This mailbox is not registered. - :http:statuscode:`429 Too Many Requests`: - The system is currently experiencing a too high request - load and is unable to accept the message for delivery. - The response format is given by `MailboxRateLimitedResponse`_. - - - **Details:** - - .. _MailboxMetadata: - .. ts:def:: MailboxMetadata - - interface MailboxMetadata { - - // The mailbox signing key. - // Note that ``$H_MAILBOX == H(signing_key)``. - // Note also how this key cannot be updated - // as it identifies the mailbox. - // Base32 crockford-encoded. - signing_key: string; - - // Type of key. - // Currently only - // EdDSA keys are supported. - signing_key_type: "EdDSA"; - - // The mailbox encryption key. - // This is a HPKE public key - // Currently, only the X25519 format - // for use in a X25519-DHKEM (RFC 9180) - // is supported. - // Base32 crockford-encoded. - encryption_key: string; - - // Type of key. - // Currently only - // X25519 keys are supported. - encryption_key_type: "X25519"; +.. include:: mailbox/get-info-H_MAILBOX.rst - // Expiration of this mailbox. - // Unix epoch (seconds) - expiration: Timestamp; - // Optional info string that can be - // chosen by the mailbox owner. - // This may contain a Keyoxide proof for the mailbox - // in order to link it to the owners profile - info?: string; - } - - -.. http:post:: /register - - Requests the registration or update of a mailbox. - May be used to update encryption keys. - May incur cost. - The mailbox identity is given through the keys field - in the ``MailboxMetadata`` field. - - **Request** - - The body of the request must be a ``MailboxRegistrationRequest``. - - **Details:** - - .. _MailboxRegistrationRequest: - .. ts:def:: MailboxRegistrationRequest - - interface MailboxRegistrationRequest { - - // Keys to add/update for the mailbox. - mailbox_metadata: MailboxMetadata; - - // Signature by the mailbox's signing key affirming - // the update of keys, of purpose - // ``TALER_SIGNATURE_MAILBOX_REGISTER``. - // The signature is created over the SHA-512 hash - // of (encryptionKeyType||encryptionKey||expiration) - // Base32 crockford-encoded. - // The signature system is defined through the - // signing_key_type in the keys field. - signature: string; - - } - - **Response** - - :http:statuscode:`204 No Content`: - Update/creation complete. - :http:statuscode:`403 Forbidden`: - The ``signature`` is invalid. - This response comes with a standard `ErrorDetail` response. - :http:statuscode:`402 Payment Required` - Client needs to make a Taler payment before proceeding. See - standard Taler payment procedure. +.. include:: mailbox/post-register.rst ---------------- Sending messages ---------------- -.. http:post:: /$H_MAILBOX - - Puts a message into ``$H_MAILBOX``. - ``$H_MAILBOX`` is the SHA512 of an EdDSA public key. - - **Request** - - The content of the request must be the message with a size of - exactly message_body_bytes (see `VersionResponse`). - - **Response** - - :http:statuscode:`204 No Content` - Message was stored and will be delivered. - :http:statuscode:`403 Forbidden` - The specified order ID in the ``Mailbox-Order-Id`` header does not - permit sending of this message. Possible reasons include the order - being for a different message, unpaid or - malformed. - This response comes with a standard `ErrorDetail` response. - :http:statuscode:`429 Too Many Requests`: - The system is currently experiencing a too high request - load and is unable to accept the message for delivery. - The response format is given by `MailboxRateLimitedResponse`_. - :http:statuscode:`402 Payment Required` - Client needs to make a Taler payment before proceeding. See - standard Taler payment procedure. - - - **Details:** - - .. _MailboxRateLimitedResponse: - .. ts:def:: MailboxRateLimitedResponse - - interface MailboxRateLimitedResponse { - - // Taler error code, TALER_EC_MAILBOX_DELIVERY_RATE_LIMITED. - code: Integer; - - // When the client should retry. - retry_delay: RelativeTime; - - // The human readable error message. - hint: string; - - } +.. include:: mailbox/post-H_MAILBOX.rst ------------------ Receiving messages ------------------ -.. http:get:: /$H_MAILBOX - - Endpoint that returns unread messages in ``$H_MAILBOX``. - The number of messages returned by the service can be limited. - If the request is simply repeated, the same messages will be - returned again (or possibly more if additional messages arrived - and the total number is below the service's current internal limit). - To receive additional messages, the client generally has to first - explicitly delete already downloaded messages from the mailbox. - If messages are returned, the ``ETag`` header will be set - containing the ID of the first message - for use in any potential delete requests that require the message ID. - - **Request:** - - :query timeout_ms=NUMBER: *Optional.* If specified, - the Mailbox service will wait up to ``NUMBER`` - milliseconds for the arrival of new messages - before sending the HTTP response. Note that if the - mailbox is non-empty, the service will always return - immediately with the messages in the mailbox, and not - wait for additional messages to arrive. - - **Response** - - :http:statuscode:`200 Ok`: - Messages are returned in binary format, 256 bytes per message, - starting with the ephemeral key and followed by - the encrypted body. Messages are not encapsulated in JSON! - :http:statuscode:`204 No Content`: - The mailbox is empty. - :http:statuscode:`429 Too Many Requests`: - The system is currently experiencing a too high request - load and is unable to accept the message for delivery. - The response format is given by `MailboxRateLimitedResponse`_. - -.. http:delete:: /$ADDRESS - - Requests the deletion of already received messages from the - mailbox. Here, ``$ADDRESS`` must be the EdDSA public key - of the mailbox (not the hash!). - The ``ETag`` header returned by a GET request for messages - returns the ID for the first message received. - This allows the caller to select a range of messages starting - from the first message received in the last GET call - to delete. - - **Request** - - The header ``Match-If`` must be set to the ID of the first message - to delete. - The ``ETag`` value is retrieved when receiving messages via a GET - request. - For example, a ``Match-If`` header value of 2 and a count field of - 5 will delete messages from ID 2 to N such that up to 5 messages are - deleted. - The ``Taler-Mailbox-Delete-Signature`` header must be set with a - Base32-Crockfor encoded signature over four 32 bit values in - network byte order: ``NBO(16)||NBO(TALER_SIGNATURE_MAILBOX_DELETE_MESSAGES)||NBO(Etag)||NBO(count)`` - where ``TALER_SIGNATURE_MAILBOX_DELETE_MESSAGES`` is a signature purpose value registered in - GANA. - - :query count=NUMBER: *Optional.* If specified, - the Mailbox service will delete up to ``NUMBER`` - of new messages starting from the ID provided - in ``Match-If``. - If the parameter is not provided, only a single - message will be deleted. - - - **Details:** - - .. _MessageDeletionRequest: - .. ts:def:: MessageDeletionRequest - - interface MessageDeletionRequest { - - // Number of messages to delete. (Starting from the beginning - // of the latest GET response). - count: Integer; - - // Signature by the mailbox's private key affirming - // the deletion of the messages, of purpuse - // ``TALER_SIGNATURE_MAILBOX_DELETE_MESSAGES``. - signature: string; - - } - - **Response** - - :http:statuscode:`204 No Content`: - Deletion complete. - :http:statuscode:`403 Forbidden`: - The ``signature`` is invalid. - This response comes with a standard `ErrorDetail` response. - :http:statuscode:`404 Not found`: - The checksum does not match the messages currently at the - head of the mailbox, or ``count`` is larger - than the number of messages currently in the mailbox. - This response comes with a standard `ErrorDetail` response. +.. include:: mailbox/get-H_MAILBOX.rst + +.. include:: mailbox/delete-ADDRESS.rst diff --git a/core/api-taldir.rst b/core/api-taldir.rst @@ -69,219 +69,21 @@ The current protocol version is **v0**. Configuration information ------------------------- -.. http:get:: /config - - Return the protocol version and currency supported by this service. - - **Response:** - - :http:statuscode:`200 OK`: - The body is a `VersionResponse`. - - .. ts:def:: VersionResponse - - interface VersionResponse { - // libtool-style representation of the Merchant protocol version, see - // https://www.gnu.org/software/libtool/manual/html_node/Versioning.html#Versioning - // The format is "current:revision:age". - version: string; - - // Name of the protocol. - name: "taler-directory"; - - // Supported alias types - alias_types: TaldirAliasType[]; - - // fee for one month of registration - monthly_fee: Amount; - - } - - .. ts:def:: TaldirAliasType - - interface TaldirAliasType { - // Name of the alias type, e.g. "email" or "sms". - name: string; - - // per challenge fee - challenge_fee: Amount; - - } +.. include:: taldir/get-config.rst ------------------ Alias registration ------------------ -.. http:post:: /register/$ALIASTYPE - - Endpoint to register, extend or modify the registration for an alias in - the directory. - Here, $ALIASTYPE is the type of alias to register, e.g. "email", or "phone". - Supported alias types are listed in the VersionResponse. - Note that duration should be given as a multiple of a month in microseconds. - If the duration is not a multiple of a month it will be rounded to the - nearest multiple. Halfway values will be rounded away from zero. - The cost calculation and resulting registration validity will be adjusted - automatically. - In order to only modify the data, the duration may be set to 0. - When the call is made with unmodified data and a duration of 0, the - endpoint will return how long this registration is currently paid for. - In order to delete the mapping, the target URI may be set to the empty string. - When the call is made with the empty string, and upon re-validation, the mapping - will be deleted. - - **Request** - - .. ts:def:: IdentityMessage +.. include:: taldir/post-register-ALIASTYPE.rst - interface IdentityMessage { - // Alias, in $ALIASTYPE-specific format - alias: string; - - // Target URI to associate with this alias. - target_uri: string; - - // For how long should the registration last/be extended. - duration: RelativeTime; - } +.. include:: taldir/get-register-H_ALIAS-PINTAN.rst - **Response** - - :http:statuscode:`200 Ok` - Registration already exists for this alias for the specified duration. - Returns for how long this registration is paid for. - The response format is given by `AlreadyPaidResponse`_. - :http:statuscode:`202 Accepted` - Registration was initiated, the client should check for receiving - a challenge at the alias where registration was attempted. - :http:statuscode:`402 Payment Required` - Client needs to make a Taler payment before proceeding. See - standard Taler payment procedure. - :http:statuscode:`404 Not found` - The TalDir service does not support the specified alias type. - This response comes with a standard `ErrorDetail` response. - :http:statuscode:`429 Too Many Requests`: - The client exceeded the number of allowed attempts for initiating - a challenge for this alias in the given timeframe. - The response format is given by `RateLimitedResponse`_. - - .. _RateLimitedResponse: - .. ts:def:: RateLimitedResponse - - interface RateLimitedResponse { - - // Taler error code, TALER_EC_TALDIR_REGISTER_RATE_LIMITED. - code: Integer; - - // At what frequency are new registrations allowed. - request_frequency: RelativeTime; - - // The human readable error message. - hint: string; - - } - - .. _AlreadyPaidResponse: - .. ts:def:: AlreadyPaidResponse - - interface AlreadyPaidResponse { - - // The remaining duration for which this registration is still paid for - valid_for: RelativeTime; - - } - - -.. http:get:: /register/$H_ALIAS/$PINTAN?alias=$ALIAS - - Endpoint that generates an HTML Web site with a link for completing the - registration. Useful to open the registration challenge in a browser (say if - it was received on a different device than where the wallet is running). - Does NOT complete the registration, as some providers automatically click on - all links in messages. Yes, we do not like them doing so either, but ``GET`` - is a "safe" method according to the HTTP standard, so technically this is - allowed. - - Opening the link will allow the user to do the POST call to this endpoint. - If the Taler wallet can somehow intercept the URL (say for SMS, if it has the right - permissions) it can skip this request and directly do the POST, as all of - the required new information is already encoded in the URL. - - Note that the wallet must be involved before the POST is made, as the - ``target_uri`` from the registration must be hashed with the ``$PINTAN`` - to protect the user against phishing. Otherwise, someone else might attempt - a concurrent registration of a different public key, and the user might - accidentally authorize the registration of the public key of a different - wallet. - ``$H_ALIAS`` is the SHA-512 hash of a prefix-free encoding of the - alias to be registered in Crockford Base32 encoding, specifically: - ``SHA-512(len($ALIASTYPE)+len($ALIAS)||$ALIASTYPE||$ALIAS)`` - The service verifies that ``$ALIAS`` is, in fact, the preimage of ``$H_ALIAS`` - and ``$ALIAS`` as well as the ``inbox_uri`` are displayed to the user - for verification. - -.. http:post:: /$H_ALIAS - - This request is the last step of a registration, proving to the TalDir that - the user of the wallet is indeed able to receive messages for the specified - alias. - ``$H_ALIAS`` is the SHA-512 hash of a prefix-free encoding of the - alias to be registered in Crockford Base32 encoding. - - **Request** - - .. ts:def:: IdentityConfirmation - - interface IdentityConfirmation { - // The solution is the SHA-512 hash of the challenge ($PINTAN) value - // chosen by TalDir concatenated with the ``inbox_uri`` (both strings - // are hashed excluding the 0-terminator). - // The hash is provided as string in Crockford base32 encoding. - solution: HashCode; - - } - - **Response** - - :http:statuscode:`204 No Content`: - Registration complete. - :http:statuscode:`403 Forbidden`: - The ``solution`` is invalid. Retrying immediately is allowed. - :http:statuscode:`404 Not found`: - The alias is unknown (original registration attempt may have expired). - :http:statuscode:`429 Too Many Requests`: - The client exceeded the number of allowed attempts for solving - a challenge for this alias in the given timeframe. +.. include:: taldir/post-H_ALIAS.rst ------------ Alias lookup ------------ -.. http:get:: /$H_ALIAS - - Lookup the target URI associated with - an alias in the TalDir. Here, - ``$H_ALIAS`` is the SHA-512 hash of a prefix-free encoding of the - alias to be registered in Crockford base32 encoding. - - **Response** - - Standard HTTP cache control headers are used to specify how long the - registration is still expected to be valid. - - :http:statuscode:`200 Ok`: - Registration information returned, of type `MailboxDetailResponse` - :http:statuscode:`404 Not found`: - The alias is unknown (original registration may have expired). - - .. _MailboxDetailResponse: - .. ts:def:: MailboxDetailResponse - - interface MailboxDetailResponse { - - // Target URI to associate with this alias. - target_uri: string; - - - } +.. include:: taldir/get-H_ALIAS.rst diff --git a/core/bank-account-directory/get-config.rst b/core/bank-account-directory/get-config.rst @@ -0,0 +1,27 @@ +.. http:get:: /config + + Return the protocol version and configuration information about the bank. + + **Response:** + + :http:statuscode:`200 OK`: + The exchange responds with a `AccountDirectoryConfig` object. This request should + virtually always be successful. + + **Details:** + + .. ts:def:: AccountDirectoryConfig + + interface AccountDirectoryConfig { + // Name of the API. + name: "taler-bank-account-directory"; + + // libtool-style representation of the Bank protocol version, see + // https://www.gnu.org/software/libtool/manual/html_node/Versioning.html#Versioning + // + // The format is "current:revision:age". + version: string; + + // URN of the implementation (needed to interpret 'revision' in version). + implementation?: string; + } diff --git a/core/bank-account-directory/get-search.rst b/core/bank-account-directory/get-search.rst @@ -0,0 +1,34 @@ +.. http:get:: /search + + Search for user accounts from user query. + + **Request:** + + :query keywords: + Textual search keywords. The fields matched depends on the bank. It can be a name, a login or any other identifier. + + **Response:** + + :http:statuscode:`200 OK`: + Response is a `Accounts`. + :http:statuscode:`204 No content`: + No accounts match this query. + + + **Details:** + + .. ts:def:: Accounts + + interface Accounts { + accounts: Account[]; + } + + .. ts:def:: Account + + interface Account { + // Formatted user information to be displayed. + display: string; + + // Full payto URI of this bank account. + payto_uri: string; + } diff --git a/core/bank-conversion-info/get-cashin-rate.rst b/core/bank-conversion-info/get-cashin-rate.rst @@ -0,0 +1,50 @@ +.. http:get:: /cashin-rate + + This public endpoint allows clients to calculate + the exchange rate between the regional currency + and the fiat currency of the banking system. + + This endpoint shows how the bank would apply the cash-in + ratio and fee to one input amount. Typically, wallets would + request this endpoint before creating withdrawals that involve + a currency conversion. + + **Request:** + + :query amount_debit: this is the amount that the user will get + deducted from their fiat bank account. + + or + + :query amount_credit: this is the amount that the user will receive + in their regional bank account. + + **Response:** + + :http:statuscode:`200 OK`: + Response is a `CashinConversionResponse`. + :http:statuscode:`400 Bad request`: + * ``TALER_EC_GENERIC_PARAMETER_MISSING`` : none of the parameters have been provided. + * ``TALER_EC_GENERIC_PARAMETER_MALFORMED`` : both of the parameters have been provided or one of them is not a valid Taler amount. + * ``TALER_EC_GENERIC_CURRENCY_MISMATCH`` : the parameter is in the wrong currency. + :http:statuscode:`401 Unauthorized`: + Invalid credentials or missing rights. + :http:statuscode:`403 Forbidden`: + Missing rights. + :http:statuscode:`409 Conflict`: + The amount is too small to be converted because it produces an amount less than zero. + :http:statuscode:`501 Not implemented`: + This server does not support conversion, client should check config response. + + **Details:** + + .. ts:def:: CashinConversionResponse + + interface CashinConversionResponse { + // Amount that the user will get deducted from their fiat + // bank account, according to the 'amount_credit' value. + amount_debit: Amount; + // Amount that the user will receive in their regional + // bank account, according to 'amount_debit'. + amount_credit: Amount; + } diff --git a/core/bank-conversion-info/get-cashout-rate.rst b/core/bank-conversion-info/get-cashout-rate.rst @@ -0,0 +1,49 @@ +.. http:get:: /cashout-rate + + This public endpoint allows clients to calculate + the exchange rate between the regional currency + and the fiat currency of the banking system. + + This endpoint shows how the bank would apply the cash-out + ratio and fee to one input amount. Typically, frontends + ask this endpoint before creating cash-in operations. + + **Request:** + + :query amount_debit: this is the amount that the user will get + deducted from their regional bank account. + + or + + :query amount_credit: this is the amount that the user will receive + in their fiat bank account. + + **Response:** + + :http:statuscode:`200 OK`: + Response is a `CashoutConversionResponse`. + :http:statuscode:`400 Bad request`: + * ``TALER_EC_GENERIC_PARAMETER_MISSING`` : none of the parameters have been provided. + * ``TALER_EC_GENERIC_PARAMETER_MALFORMED`` : both of the parameters have been provided or one of them is not a valid Taler amount. + * ``TALER_EC_GENERIC_CURRENCY_MISMATCH`` : the parameter is in the wrong currency. + :http:statuscode:`401 Unauthorized`: + Invalid credentials or missing rights. + :http:statuscode:`403 Forbidden`: + Missing rights. + :http:statuscode:`409 Conflict`: + The amount is too small to be converted because it produces an amount less than zero. + :http:statuscode:`501 Not implemented`: + This server does not support conversion, client should check config response. + + **Details:** + + .. ts:def:: CashoutConversionResponse + + interface CashoutConversionResponse { + // Amount that the user will get deducted from their regional + // bank account, according to the 'amount_credit' value. + amount_debit: Amount; + // Amount that the user will receive in their fiat + // bank account, according to 'amount_debit'. + amount_credit: Amount; + } diff --git a/core/bank-conversion-info/get-config.rst b/core/bank-conversion-info/get-config.rst @@ -0,0 +1,45 @@ +.. http:get:: /config + + Return the protocol version and configuration information about the bank. + + **Response:** + + :http:statuscode:`200 OK`: + Response is a `ConversionConfig`. + :http:statuscode:`501 Not implemented`: + This server does not support conversion, client should check config response. + + **Details:** + + .. ts:def:: ConversionConfig + + interface ConversionConfig { + // libtool-style representation of the Bank protocol version, see + // https://www.gnu.org/software/libtool/manual/html_node/Versioning.html#Versioning + // The format is "current:revision:age". + version: string; + + // Name of the API. + name: "taler-conversion-info"; + + // URN of the implementation (needed to interpret 'revision' in version). + // @since v4, may become mandatory in the future. + implementation?: string; + + // Currency used by this bank. + regional_currency: string; + + // How the bank SPA should render this currency. + regional_currency_specification: CurrencySpecification; + + // External currency used during conversion. + fiat_currency: string; + + // How the bank SPA should render this currency. + fiat_currency_specification: CurrencySpecification; + + // Global exchange rate between the regional currency and the fiat + // currency of the banking system. Use /rate to get the user specific + // rate. + conversion_rate: ConversionRate; + } diff --git a/core/bank-conversion-info/get-rate.rst b/core/bank-conversion-info/get-rate.rst @@ -0,0 +1,15 @@ +.. http:get:: /rate + + Since protocol **v2**. + + This public endpoint allows clients to get the currenlty applied change rate between the regional currency and the fiat currency of the banking system for this exchange account. + Those informations should never be used to perform conversions use ``/cashin-rate`` and ``/cashout-rate`` instead. + Conversion rates can change at any time. Clients must deal with any resulting errors and call ``/cashin-rate`` or ``/cashout-rate`` again to use the new rates. + If ``cashin_ratio`` is zero, this means the account cannot cashin, and if ``cash_out`` ratio is zero, this means the account cannot cashout. + + **Response:** + + :http:statuscode:`200 OK`: + Response is a `ConversionRate`. + :http:statuscode:`501 Not implemented`: + This server does not support conversion. diff --git a/core/bank-conversion-info/post-conversion-rate.rst b/core/bank-conversion-info/post-conversion-rate.rst @@ -0,0 +1,54 @@ +.. http:post:: /conversion-rate + + This endpoint allows the administrator to update the global exchange rate between the regional currency and the fiat currency of the banking system. Individual users can have different rate if they are part of an conversion rate classe. + + The conversion is calculated as follows: ``(amount * ratio - fee) / tiny_amount``. + + Only available to the administrator. + + **Request:** + + .. ts:def:: ConversionRate + + interface ConversionRate { + // Minimum fiat amount authorised for cashin before conversion + cashin_min_amount: Amount; + + // Exchange rate to buy regional currency from fiat + cashin_ratio: DecimalNumber; + + // Regional amount fee to subtract after applying the cashin ratio. + cashin_fee: Amount; + + // Smallest possible regional amount, converted amount is rounded to this amount + cashin_tiny_amount: Amount; + + // Rounding mode used during cashin conversion + cashin_rounding_mode: "zero" | "up" | "nearest"; + + // Minimum regional amount authorised for cashout before conversion + cashout_min_amount: Amount; + + // Exchange rate to sell regional currency for fiat + cashout_ratio: DecimalNumber; + + // Fiat amount fee to subtract after applying the cashout ratio. + cashout_fee: Amount; + + // Smallest possible fiat amount, converted amount is rounded to this amount + cashout_tiny_amount: Amount; + + // Rounding mode used during cashout conversion + cashout_rounding_mode: "zero" | "up" | "nearest"; + } + + **Response:** + + :http:statuscode:`204 No content`: + Operation successful. + :http:statuscode:`401 Unauthorized`: + Invalid credentials or missing rights. + :http:statuscode:`403 Forbidden`: + Missing rights. + :http:statuscode:`501 Not implemented`: + This server does not support conversion, client should check config response. diff --git a/core/bank-integration/get-config.rst b/core/bank-integration/get-config.rst @@ -0,0 +1,34 @@ +.. http:get:: /config + + Return the protocol version and configuration information about the bank. + + **Response:** + + :http:statuscode:`200 OK`: + The exchange responds with a `IntegrationConfig` object. This request should + virtually always be successful. + + **Details:** + + .. ts:def:: IntegrationConfig + + interface IntegrationConfig { + // Name of the API. + name: "taler-bank-integration"; + + // libtool-style representation of the Bank protocol version, see + // https://www.gnu.org/software/libtool/manual/html_node/Versioning.html#Versioning + // + // The format is "current:revision:age". + version: string; + + // URN of the implementation (needed to interpret 'revision' in version). + // @since **v2**, may become mandatory in the future. + implementation?: string; + + // Currency used by this bank. + currency: string; + + // How the bank SPA should render this currency. + currency_specification: CurrencySpecification; + } diff --git a/core/bank-integration/get-withdrawal-operation-WITHDRAWAL_ID.rst b/core/bank-integration/get-withdrawal-operation-WITHDRAWAL_ID.rst @@ -0,0 +1,125 @@ +.. http:get:: /withdrawal-operation/$WITHDRAWAL_ID + + Query information about a withdrawal operation, identified by the ``WITHDRAWAL_ID``. + + **Request:** + + :query timeout_ms: *Optional.* + Timeout in milliseconds, for :ref:`long-polling <long-polling>`, to wait for operation state to be different from ``old_state``. Since protocol **v3**. + :query old_state: + *Optional.* Defaults to "pending". + :query long_poll_ms: *Optional.* + Deprecated in protocol **v3**. Use *timeout_ms* instead. + + **Response:** + + :http:statuscode:`200 OK`: + The withdrawal operation is known to the bank, and details are given + in the `BankWithdrawalOperationStatus` response body. + :http:statuscode:`404 Not found`: + The operation was not found. + + **Details:** + + .. ts:def:: BankWithdrawalOperationStatus + + interface BankWithdrawalOperationStatus { + // Current status of the operation + // pending: the operation is pending parameters selection (exchange and reserve public key) + // selected: the operations has been selected and is pending confirmation + // aborted: the operation has been aborted + // confirmed: the transfer has been confirmed and registered by the bank + // @since **v1** + status: "pending" | "selected" | "aborted" | "confirmed"; + + // Currency used for the withdrawal. + // MUST be present when amount is absent. + // @since **v2**, may become mandatory in the future. + currency?: string; + + // Amount that will be withdrawn with this operation + // (raw amount without fee considerations). Only + // given once the amount is fixed and cannot be changed. + // Optional since **v4**. + amount?: Amount; + + // Suggestion for the amount to be withdrawn with this + // operation. Given if a suggestion was made but the + // user may still change the amount. + // Optional since **v4**. + suggested_amount?: Amount; + + // Minimum amount that the wallet can choose to withdraw. + // Only applicable when the amount is not fixed. + // @since **v4**. + min_amount?: Amount; + + // Maximum amount that the wallet can choose to withdraw. + // Only applicable when the amount is not fixed. + // @since **v4**. + max_amount?: Amount; + + // The non-Taler card fees the customer will have + // to pay to the bank / payment service provider + // they are using to make the withdrawal in addition + // to the amount. + // @since **v4** + card_fees?: Amount; + + // Bank account of the customer that is debiting, as a + // full RFC 8905 ``payto`` URI. + sender_wire?: string; + + // Base URL of the suggested exchange. The bank may have + // neither a suggestion nor a requirement for the exchange. + // This value is typically set in the bank's configuration. + suggested_exchange?: string; + + // Base URL of an exchange that must be used. Optional, + // not given *unless* a particular exchange is mandatory. + // This value is typically set in the bank's configuration. + // @since **v4** + required_exchange?: string; + + // URL that the user needs to navigate to in order to + // complete some final confirmation (e.g. 2FA). + // Only applicable when ``status`` is ``selected`` or ``pending``. + // It may contain the withdrawal operation id. + confirm_transfer_url?: string; + + // Wire transfer types supported by the bank. + wire_types: string[]; + + // Reserve public key selected by the exchange, + // only non-null if ``status`` is ``selected`` or ``confirmed``. + // @since **v1** + selected_reserve_pub?: EddsaPublicKey; + + // Exchange account selected by the wallet; + // only non-null if ``status`` is ``selected`` or ``confirmed``. + // @since **v1** + selected_exchange_account?: string; + + // If true, tells the wallet not to allow the user to + // specify an amount to withdraw and to not provide + // any amount when registering with the withdrawal + // operation. The amount to withdraw will be set + // by the final ``/withdrawals/$WITHDRAWAL_ID/confirm`` step. + // @since **v5** + no_amount_to_wallet?: boolean; + + // @deprecated since **v1**, use ``status`` instead + // Indicates whether the withdrawal was aborted. + aborted: boolean; + + // @deprecated since **v1**, use ``status`` instead + // Has the wallet selected parameters for the withdrawal operation + // (exchange and reserve public key) and successfully sent it + // to the bank? + selection_done: boolean; + + // @deprecated since **v1**, use ``status`` instead + // The transfer has been confirmed and registered by the bank. + // Does not guarantee that the funds have arrived at the exchange already. + transfer_done: boolean; + } diff --git a/core/bank-integration/post-withdrawal-operation-WITHDRAWAL_ID-abort.rst b/core/bank-integration/post-withdrawal-operation-WITHDRAWAL_ID-abort.rst @@ -0,0 +1,22 @@ +.. http:post:: /withdrawal-operation/$WITHDRAWAL_ID/abort + + Aborts ``WITHDRAWAL_ID`` operation. Has no effect on an already aborted + operation. This endpoint can be used by the wallet if the user aborts + the transaction, ensuring that the operation is also aborted at the + bank. + + Since protocol **v2**. + + **Request:** + + The request body is empty. + + **Response:** + + :http:statuscode:`204 No content`: + The withdrawal operation has been aborted. + :http:statuscode:`404 Not found`: + The withdrawal operation was not found. + :http:statuscode:`409 Conflict`: + The withdrawal operation has been confirmed previously and + can't be aborted. diff --git a/core/bank-integration/post-withdrawal-operation-WITHDRAWAL_ID.rst b/core/bank-integration/post-withdrawal-operation-WITHDRAWAL_ID.rst @@ -0,0 +1,67 @@ +.. http:post:: /withdrawal-operation/$WITHDRAWAL_ID + + This endpoint is used by the GNU Taler wallet to supply additional + details needed to complete a withdraw operation. + + **Request:** + + .. ts:def:: BankWithdrawalOperationPostRequest + + interface BankWithdrawalOperationPostRequest { + + // Reserve public key that should become the wire transfer + // subject to fund the withdrawal. + reserve_pub: EddsaPublicKey; + + // Full RFC 8905 (payto) address of the exchange account to be + // credited for the withdrawal. + selected_exchange: string; + + // Selected amount to be transferred. Optional if the + // backend already knows the amount. + // @since **v4** + amount?: Amount; + } + + **Response:** + + :http:statuscode:`200 OK`: + The bank has accepted the withdrawal operation parameters chosen by the wallet. + The response is a `BankWithdrawalOperationPostResponse`. + :http:statuscode:`404 Not found`: + The bank does not know about a withdrawal operation with the specified ``WITHDRAWAL_ID``. + :http:statuscode:`409 Conflict`: + * ``TALER_EC_BANK_UPDATE_ABORT_CONFLICT`` : the withdrawal has been aborted previously and can't be modified. + * ``TALER_EC_BANK_WITHDRAWAL_OPERATION_RESERVE_SELECTION_CONFLICT``: + The wallet selected a different exchange or reserve public key under the same withdrawal ID. + * ``TALER_EC_BANK_DUPLICATE_RESERVE_PUB_SUBJECT``: the reserve public key is already used. + * ``TALER_EC_BANK_UNKNOWN_ACCOUNT``: the selected exchange account was not found. + * ``TALER_EC_BANK_ACCOUNT_IS_NOT_EXCHANGE``: the selected account is not an exchange. + * ``TALER_EC_BANK_AMOUNT_DIFFERS`` : the specified amount will not work for this + withdrawal (since **v4**). + * ``TALER_EC_BANK_UNALLOWED_DEBIT`` : the account does not have sufficient funds or the amount is too low or too high (since **v4**). + + **Details:** + + .. ts:def:: BankWithdrawalOperationPostResponse + + interface BankWithdrawalOperationPostResponse { + // Current status of the operation + // pending: the operation is pending parameters selection (exchange and reserve public key) + // selected: the operations has been selected and is pending confirmation + // aborted: the operation has been aborted + // confirmed: the transfer has been confirmed and registered by the bank + status: "selected" | "aborted" | "confirmed"; + + // URL that the user needs to navigate to in order to + // complete some final confirmation (e.g. 2FA). + // + // Only applicable when ``status`` is ``selected`` or ``pending``. + // It may contain withdrawal operation id + confirm_transfer_url?: string; + + // @deprecated since **v1**, use ``status`` instead + // The transfer has been confirmed and registered by the bank. + // Does not guarantee that the funds have arrived at the exchange already. + transfer_done: boolean; + } diff --git a/core/bank-revenue/get-config.rst b/core/bank-revenue/get-config.rst @@ -0,0 +1,30 @@ +.. http:get:: /config + + Return the protocol version and configuration information about the bank. + + **Response:** + + :http:statuscode:`200 OK`: + The exchange responds with a `RevenueConfig` object. This request should + virtually always be successful. + + **Details:** + + .. ts:def:: RevenueConfig + + interface RevenueConfig { + // Name of the API. + name: "taler-revenue"; + + // libtool-style representation of the Bank protocol version, see + // https://www.gnu.org/software/libtool/manual/html_node/Versioning.html#Versioning + // The format is "current:revision:age". + version: string; + + // Currency used by this gateway. + currency: string; + + // URN of the implementation (needed to interpret 'revision' in version). + // @since v0, may become mandatory in the future. + implementation?: string; + } diff --git a/core/bank-revenue/get-history.rst b/core/bank-revenue/get-history.rst @@ -0,0 +1,74 @@ +.. http:get:: /history + + Return a list of transactions made to an account. + + The bank account is determined via the base URL and/or the + user name in the ``Authorization`` header. In fact, the transaction history + might come from a "virtual" account, where multiple real bank accounts are + merged into one history. + + Transactions are identified by an opaque ``row_id`` numerical identifier. Its semantics (including its sorting order) are determined by the bank server and are completely opaque to the client. + + **Request:** + + :query limit: *Optional.* + At most return the given number of results. Negative for descending by ``row_id``, positive for ascending by ``row_id``. Defaults to ``-20``. Since protocol v1. + :query offset: *Optional.* + Starting ``row_id`` for :ref:`pagination <row-id-pagination>`. Since protocol v1. + :query timeout_ms: *Optional.* + Timeout in milliseconds, for :ref:`long-polling <long-polling>`, to wait for at least one element to be shown. Only useful if *limit* is positive. Since protocol v1. + :query delta: *Optional.* + Deprecated in protocol **v1**. Use *limit* instead. + :query start: *Optional.* + Deprecated in protocol **v1**. Use *offset* instead. + :query long_poll_ms: *Optional.* + Deprecated in protocol **v1**. Use *timeout_ms* instead. + + **Response:** + + :http:statuscode:`200 OK`: + JSON object of type `RevenueIncomingHistory`. + :http:statuscode:`400 Bad request`: + Request malformed. The bank replies with an `ErrorDetail` object. + :http:statuscode:`401 Unauthorized`: + Authentication failed, likely the credentials are wrong. + :http:statuscode:`404 Not found`: + The endpoint is wrong or the user name is unknown. The bank replies with an `ErrorDetail` object. + + **Details:** + + .. ts:def:: RevenueIncomingHistory + + interface RevenueIncomingHistory { + // Array of incoming transactions. + incoming_transactions : RevenueIncomingBankTransaction[]; + + // Full payto URI to identify the receiver of funds. + // Credit account is shared by all incoming transactions + // as per the nature of the request. + credit_account: string; + } + + .. ts:def:: RevenueIncomingBankTransaction + + interface RevenueIncomingBankTransaction { + // Opaque identifier of the returned record. + row_id: SafeUint64; + + // Date of the transaction. + date: Timestamp; + + // Amount received before credit_fee. + amount: Amount; + + // Fee payed by the creditor. + // If not null, creditor actually received amount - credit_fee + // @since **v1** + credit_fee?: Amount; + + // Full payto URI to identify the sender of funds. + debit_account: string; + + // The wire transfer subject. + subject: string; + } diff --git a/core/bank-transfer/get-config.rst b/core/bank-transfer/get-config.rst @@ -0,0 +1,41 @@ +.. http:get:: /config + + Return the protocol version and configuration information about the adapter. + This specification corresponds to ``current`` protocol being version **1**. + + **Response:** + + :http:statuscode:`200 OK`: + The adapter responds with a `PreparedTransferConfig` object. This request + should virtually always be successful. + + **Details:** + + .. ts:def:: SubjectFormat + + type SubjectFormat = + | "SIMPLE" + | "URI" + | "CH_QR_BILL"; + + .. ts:def:: PreparedTransferConfig + + interface PreparedTransferConfig { + // Name of the API. + name: "taler-prepared-transfer"; + + // libtool-style representation of the protocol version, see + // https://www.gnu.org/software/libtool/manual/html_node/Versioning.html#Versioning + // The format is "current:revision:age". + version: string; + + // Currency used by this API. + currency: string; + + // URN of the implementation (needed to interpret 'revision' in version). + // @since v0, may become mandatory in the future. + implementation?: string; + + // Supported formats for registration, there must at least one. + supported_formats: SubjectFormat[]; + } diff --git a/core/bank-transfer/post-registration.rst b/core/bank-transfer/post-registration.rst @@ -0,0 +1,119 @@ +.. http:post:: /registration + + Register a public key for wire transfer use. + + This endpoint generate appropriate subjects to link a transfer to the + registered public key. + + Two public keys must be provided, the ``account_pub`` key is the key that + will forwarded to the exchange and the ``authorization_pub`` key will be + encoded inside the subject. + + For simple one time wire transfers, use the same key for both ``account_pub`` + and ``authorization_pub``. For recurrent transfers, use a single + ``authorization_pub`` for different ``account_pub``. + + If registered as ``recurrent`` the wire adapters will keep incoming transfers + reusing the same subject until a registration is performed, else it will + bounce. + + Registration with the same ``authorization_pu`` will replace the existing information registered for the key. + + **Request:** + + .. ts:def:: RegistrationRequest + + interface RegistrationRequest { + // Amount to transfer + credit_amount: Amount; + + // Transfer types + type: "reserve" | "kyc"; + + // Public key algorithm + alg: "EdDSA"; + + // Account public key for the exchange + account_pub: EddsaPublicKey; + + // Public key encoded inside the subject + authorization_pub: EddsaPublicKey; + + // Signature of the account_pub key using the authorization_pub private key + authorization_sig: EddsaSignature; + + // Whether the authorization_pub will be reused for recurrent transfers + // Disable bounces in case of authorization_pub reuse + recurrent: boolean; + } + + **Response:** + + :http:statuscode:`200 Ok`: + Response is a `RegistrationResponse`. + :http:statuscode:`400 Bad request`: + Input data was invalid. + :http:statuscode:`409 Conflict`: + * ``TALER_EC_BANK_DUPLICATE_RESERVE_PUB_SUBJECT``: the same reserve public key is already registered, you should retry using another key. + * ``TALER_EC_BANK_DERIVATION_REUSE``: derived subject is already used, you should retry using another key. + * ``TALER_EC_BANK_BAD_SIGNATURE``: signature is invalid. + + **Details:** + + .. ts:def:: TransferSubject + + // Union discriminated by the "type" field. + type TransferSubject = + | SimpleSubject + | UriSubject + | SwissQrBillSubject; + + .. ts:def:: SimpleSubject + + interface SimpleSubject { + // Subject for system accepting large subjects + type: "SIMPLE"; + + // Amount to transfer + credit_amount: Amount; + + // Encoded string containing either the full key and transfer type or a + // derived short subject + subject: string; + } + + .. ts:def:: UriSubject + + interface UriSubject { + // Subject for system accepting prepared payments + type: "URI"; + + // Amount to transfer + credit_amount: Amount; + + // Prepared payments confirmation URI + uri: string; + } + + .. ts:def:: SwissQrBillSubject + + interface SwissQrBillSubject { + // Subject for Swiss QR Bill + type: "CH_QR_BILL"; + + // Amount to transfer + credit_amount: Amount; + + // 27-digit QR Reference number + qr_reference_number: string; + } + + .. ts:def:: RegistrationResponse + + interface RegistrationResponse { + // The transfer subject encoded in all supported formats + subjects: TransferSubject[]; + + // Expiration date after which this subject is expected to be reused + expiration: Timestamp; + } diff --git a/core/bank-transfer/post-unregistration.rst b/core/bank-transfer/post-unregistration.rst @@ -0,0 +1,34 @@ +.. http:post:: /unregistration + + Remove an existing registered public key for wire transfer use. + + Use this endpoint to free a derived subject or cancel a recurrent paiment. + + + **Request:** + + .. ts:def:: Unregistration + + interface Unregistration { + // Current timestamp in the ISO 8601 + timestamp: string; + + // Public key used for registration + authorization_pub: EddsaPublicKey; + + // Signature of the timestamp using the authorization_pub private key + // Prevent replay attack + authorization_sig: EddsaSignature; + } + + **Response:** + + :http:statuscode:`204 No content`: + The registration have been deleted. + :http:statuscode:`400 Bad request`: + Input data was invalid. + :http:statuscode:`404 Not found`: + Unknown registration. + :http:statuscode:`409 Conflict`: + * ``TALER_EC_BANK_OLD_TIMESTAMP``: the timestamp is too old. + * ``TALER_EC_BANK_BAD_SIGNATURE``: signature is invalid. +\ No newline at end of file diff --git a/core/bank-wire/get-account-check.rst b/core/bank-wire/get-account-check.rst @@ -0,0 +1,30 @@ +.. http:get:: /account/check + + Check account existence. + + Since protocol **v4**. + + **Request:** + + :query account: + Payto URI of the account. + + **Response:** + + :http:statuscode:`200 OK`: + JSON object of type `AccountInfo`. + :http:statuscode:`400 Bad request`: + Request malformed. The bank replies with an `ErrorDetail` object. + :http:statuscode:`401 Unauthorized`: + Authentication failed, likely the credentials are wrong. + :http:statuscode:`404 Not found`: + * ``TALER_EC_BANK_UNKNOWN_ACCOUNT``: unknown account. + :http:statuscode:`501 Not Implemented`: + This server does not support account check. + + **Details:** + + .. ts:def:: AccountInfo + + interface AccountInfo { + } diff --git a/core/bank-wire/get-config.rst b/core/bank-wire/get-config.rst @@ -0,0 +1,35 @@ +.. http:get:: /config + + Return the protocol version and configuration information about the bank. + This specification corresponds to ``current`` protocol being version **5**. + + **Response:** + + :http:statuscode:`200 OK`: + The adapter responds with a `WireConfig` object. This request should + virtually always be successful. + + **Details:** + + .. ts:def:: WireConfig + + interface WireConfig { + // Name of the API. + name: "taler-wire-gateway"; + + // libtool-style representation of the Bank protocol version, see + // https://www.gnu.org/software/libtool/manual/html_node/Versioning.html#Versioning + // The format is "current:revision:age". + version: string; + + // Currency used by this gateway. + currency: string; + + // URN of the implementation (needed to interpret 'revision' in version). + // @since v0, may become mandatory in the future. + implementation?: string; + + // Whether implementation support account existence check + // @since **v4** + support_account_check: boolean; + } diff --git a/core/bank-wire/get-history-incoming.rst b/core/bank-wire/get-history-incoming.rst @@ -0,0 +1,156 @@ +.. http:get:: /history/incoming + + Return a list of transactions made from or to the exchange. + + Incoming transactions must contain a valid reserve public key. If a bank + transaction does not conform to the right syntax, the wire gateway must not + report it to the exchange, and send funds back to the sender if possible. + + **Request:** + + :query limit: *Optional.* + At most return the given number of results. Negative for descending by ``row_id``, positive for ascending by ``row_id``. Defaults to ``-20``. Since protocol **v2**. + :query offset: *Optional.* + Starting ``row_id`` for :ref:`pagination <row-id-pagination>`. Since protocol **v2**. + :query timeout_ms: *Optional.* + Timeout in milliseconds, for :ref:`long-polling <long-polling>`, to wait for at least one element to be shown. Only useful if *limit* is positive. Since protocol **v2**. + :query delta: *Optional.* + Deprecated in protocol **v2**. Use *limit* instead. + :query start: *Optional.* + Deprecated in protocol **v2**. Use *offset* instead. + :query long_poll_ms: *Optional.* + Deprecated in protocol **v2**. Use *timeout_ms* instead. + + **Response:** + + :http:statuscode:`200 OK`: + JSON object of type `IncomingHistory`. + :http:statuscode:`204 No content`: + There are not transactions to report (under the given filter). + :http:statuscode:`400 Bad request`: + Request malformed. The bank replies with an `ErrorDetail` object. + :http:statuscode:`401 Unauthorized`: + Authentication failed, likely the credentials are wrong. + :http:statuscode:`404 Not found`: + The endpoint is wrong or the user name is unknown. The bank replies with an `ErrorDetail` object. + + **Details:** + + .. ts:def:: IncomingHistory + + interface IncomingHistory { + // Array of incoming transactions. + incoming_transactions: IncomingBankTransaction[]; + + // Full payto URI to identify the receiver of funds. + // This must be one of the exchange's bank accounts. + // Credit account is shared by all incoming transactions + // as per the nature of the request. + credit_account: string; + } + + .. ts:def:: IncomingBankTransaction + + // Union discriminated by the "type" field. + type IncomingBankTransaction = + | IncomingKycAuthTransaction + | IncomingReserveTransaction + | IncomingWadTransaction; + + .. ts:def:: IncomingKycAuthTransaction + + // Since protocol **v1**. + interface IncomingKycAuthTransaction { + type: "KYCAUTH"; + + // Opaque identifier of the returned record. + row_id: SafeUint64; + + // Date of the transaction. + date: Timestamp; + + // Amount received before credit_fee. + amount: Amount; + + // Fee paid by the creditor. + // If not null, creditor actually received amount - credit_fee + // @since **v3** + credit_fee?: Amount; + + // Full payto URI to identify the sender of funds. + debit_account: string; + + // The account public key extracted from the transaction details. + account_pub: EddsaPublicKey; + + // The authorization public key used for mapping + // @since **v5** + authorization_pub?: EddsaPublicKey; + + // Signature of the account public key using the authorization private key + // @since **v5** + authorization_sig?: EddsaSignature; + } + + .. ts:def:: IncomingReserveTransaction + + interface IncomingReserveTransaction { + type: "RESERVE"; + + // Opaque identifier of the returned record. + row_id: SafeUint64; + + // Date of the transaction. + date: Timestamp; + + // Amount received before credit_fee. + amount: Amount; + + // Fee payed by the creditor. + // If not null, creditor actually received amount - + // @since **v3** + credit_fee?: Amount; + + // Full payto URI to identify the sender of funds. + debit_account: string; + + // The reserve public key extracted from the transaction details. + reserve_pub: EddsaPublicKey; + + // The authorization public key used for mapping + // @since **v5** + authorization_pub?: EddsaPublicKey; + + // Signature of the reserve public key using the authorization private key + // @since **v5** + authorization_sig?: EddsaSignature; + } + + .. ts:def:: IncomingWadTransaction + + interface IncomingWadTransaction { + type: "WAD"; + + // Opaque identifier of the returned record. + row_id: SafeUint64; + + // Date of the transaction. + date: Timestamp; + + // Amount received before credit_fee. + amount: Amount; + + // Fee payed by the creditor. + // If not null, creditor actually received amount - credit_fee + // @since **v3** + credit_fee?: Amount; + + // Full payto URI to identify the sender of funds. + debit_account: string; + + // Base URL of the exchange that originated the wad. + origin_exchange_url: string; + + // The reserve public key extracted from the transaction details. + wad_id: WadId; + } diff --git a/core/bank-wire/get-history-outgoing.rst b/core/bank-wire/get-history-outgoing.rst @@ -0,0 +1,77 @@ +.. http:get:: /history/outgoing + + Return a list of transactions made by the exchange, typically to a merchant. + + **Request:** + + :query limit: *Optional.* + At most return the given number of results. Negative for descending by ``row_id``, positive for ascending by ``row_id``. Defaults to ``-20``. Since protocol **v2**. + :query offset: *Optional.* + Starting ``row_id`` for :ref:`pagination <row-id-pagination>`. Since protocol **v2**. + :query timeout_ms: *Optional.* + Timeout in milliseconds, for :ref:`long-polling <long-polling>`, to wait for at least one element to be shown. Only useful if *limit* is positive. Since protocol **v2**. + :query delta: *Optional.* + Deprecated in protocol **v2**. Use *limit* instead. + :query start: *Optional.* + Deprecated in protocol **v2**. Use *offset* instead. + :query long_poll_ms: *Optional.* + Deprecated in protocol **v2**. Use *timeout_ms* instead. + + **Response:** + + :http:statuscode:`200 OK`: + JSON object of type `OutgoingHistory`. + :http:statuscode:`204 No content`: + There are not transactions to report (under the given filter). + :http:statuscode:`400 Bad request`: + Request malformed. The bank replies with an `ErrorDetail` object. + :http:statuscode:`401 Unauthorized`: + Authentication failed, likely the credentials are wrong. + :http:statuscode:`404 Not found`: + The endpoint is wrong or the user name is unknown. The bank replies with an `ErrorDetail` object. + + **Details:** + + .. ts:def:: OutgoingHistory + + interface OutgoingHistory { + // Array of outgoing transactions. + outgoing_transactions: OutgoingBankTransaction[]; + + // Full payto URI to identify the sender of funds. + // This must be one of the exchange's bank accounts. + // Credit account is shared by all incoming transactions + // as per the nature of the request. + debit_account: string; + } + + .. ts:def:: OutgoingBankTransaction + + interface OutgoingBankTransaction { + // Opaque identifier of the returned record. + row_id: SafeUint64; + + // Date of the transaction. + date: Timestamp; + + // Amount transferred. + amount: Amount; + + // Fee paid by the debtor. + // If not null, debtor actually paid amount + debit_fee + // @since **v3** + debit_fee?: Amount; + + // Full payto URI to identify the receiver of funds. + credit_account: string; + + // The wire transfer ID in the outgoing transaction. + wtid: ShortHashCode; + + // Base URL of the exchange. + exchange_base_url: string; + + // Optional additional metadata. + // @since **v5** + metadata?: string; + } diff --git a/core/bank-wire/get-transfers-ROW_ID.rst b/core/bank-wire/get-transfers-ROW_ID.rst @@ -0,0 +1,60 @@ +.. http:get:: /transfers/$ROW_ID + + Return the status of a transfer initiated from the exchange, identified by the ``ROW_ID``. + + Since protocol **v3**. + + **Response:** + + :http:statuscode:`200 OK`: + The transfer is known, and details are given in the `TransferStatus` response body. + :http:statuscode:`400 Bad request`: + Request malformed. + :http:statuscode:`401 Unauthorized`: + Authentication failed, likely the credentials are wrong. + :http:statuscode:`404 Not found`: + The transfer was not found. + + **Details:** + + .. ts:def:: TransferStatus + + interface TransferStatus { + // Current status of the transfer + // pending: the transfer is in progress + // transient_failure: the transfer has failed but may succeed later + // permanent_failure: the transfer has failed permanently and will never appear in the outgoing history + // success: the transfer has succeeded and appears in the outgoing history + status: "pending" | "transient_failure" | "permanent_failure" | "success"; + + // Optional unstructured messages about the transfer's status. Can be used to document the reasons for failure or the state of progress. + status_msg?: string; + + // Amount to transfer. + amount: Amount; + + // Base URL of the exchange. Shall be included by the bank gateway + // in the appropriate section of the wire transfer details. + exchange_base_url: string; + + // Optional additional metadata to be stored in the transaction. + // @since **v5** + metadata?: string; + + // Wire transfer identifier chosen by the exchange, + // used by the merchant to identify the Taler order(s) + // associated with this wire transfer. + wtid: ShortHashCode; + + // The recipient's account identifier as a full payto URI. + credit_account: string; + + // Timestamp that indicates when the wire transfer was executed. + // In cases where the wire transfer gateway is unable to know when + // the wire transfer will be executed, the time at which the request + // has been received and stored will be returned. + // The purpose of this field is for debugging (humans trying to find + // the transaction) as well as for taxation (determining which + // time period a transaction belongs to). + timestamp: Timestamp; + } diff --git a/core/bank-wire/get-transfers.rst b/core/bank-wire/get-transfers.rst @@ -0,0 +1,78 @@ +.. http:get:: /transfers + + Return a list of transfers initiated from the exchange. + + The bank account of the exchange is determined via the base URL and/or the + user name in the ``Authorization`` header. The transfer history + might come from a "virtual" account, where multiple real bank accounts are + merged into one history. + + Since protocol **v3**. + + **Request:** + + :query limit: *Optional.* + At most return the given number of results. Negative for descending by + ``row_id``, positive for ascending by ``row_id``. Defaults to ``-20``. + :query offset: *Optional.* + Starting ``row_id`` for :ref:`pagination <row-id-pagination>`. + :query status: *Optional*. + Filters by status. + + **Response:** + + :http:statuscode:`200 OK`: + JSON object of type `TransferList`. + :http:statuscode:`204 No content`: + There are no transfers to report (under the given filter). + :http:statuscode:`400 Bad request`: + Request malformed. + :http:statuscode:`401 Unauthorized`: + Authentication failed, likely the credentials are wrong. + :http:statuscode:`404 Not found`: + The endpoint is wrong or the user name is unknown. + + **Details:** + + .. ts:def:: TransferList + + interface TransferList { + // Array of initiated transfers. + transfers: TransferListStatus[]; + + // Full payto:// URI to identify the sender of funds. + // This must be one of the exchange's bank accounts. + // Credit account is shared by all incoming transactions + // as per the nature of the request. + debit_account: string; + } + + .. ts:def:: TransferListStatus + + interface TransferListStatus { + // Opaque ID of the wire transfer initiation performed by the bank. + // It is different from the /history endpoints row_id. + row_id: SafeUint64; + + // Current status of the transfer + // pending: the transfer is in progress + // transient_failure: the transfer has failed but may succeed later + // permanent_failure: the transfer has failed permanently and will never appear in the outgoing history + // success: the transfer has succeeded and appears in the outgoing history + status: "pending" | "transient_failure" | "permanent_failure" | "success"; + + // Amount to transfer. + amount: Amount; + + // The recipient's account identifier as a full payto:// URI. + credit_account: string; + + // Timestamp that indicates when the wire transfer was executed. + // In cases where the wire transfer gateway is unable to know when + // the wire transfer will be executed, the time at which the request + // has been received and stored will be returned. + // The purpose of this field is for debugging (humans trying to find + // the transaction) as well as for taxation (determining which + // time period a transaction belongs to). + timestamp: Timestamp; + } diff --git a/core/bank-wire/post-admin-add-incoming.rst b/core/bank-wire/post-admin-add-incoming.rst @@ -0,0 +1,56 @@ +.. http:post:: /admin/add-incoming + + Simulate a transfer from a customer to the exchange. This API is *not* + idempotent since it's only used in testing. + + **Request:** + + .. ts:def:: AddIncomingRequest + + interface AddIncomingRequest { + // Amount to transfer. + amount: Amount; + + // Reserve public key that is included in the wire transfer details + // to identify the reserve that is being topped up. + reserve_pub: EddsaPublicKey; + + // Account (as full payto URI) that makes the wire transfer to the exchange. + // Usually this account must be created by the test harness before this + // API is used. An exception is the "fakebank", where any debit account + // can be specified, as it is automatically created. + debit_account: string; + } + + **Response:** + + :http:statuscode:`200 OK`: + The request has been correctly handled, so the funds have been transferred to + the recipient's account. The body is a `AddIncomingResponse`. + :http:statuscode:`400 Bad request`: + The request is malformed. The bank replies with an `ErrorDetail` object. + :http:statuscode:`401 Unauthorized`: + Authentication failed, likely the credentials are wrong. + :http:statuscode:`404 Not found`: + The endpoint is wrong or the user name is unknown. The bank replies with an `ErrorDetail` object. + :http:statuscode:`409 Conflict`: + The 'reserve_pub' argument was used previously in another transfer, and the specification mandates that reserve public keys must not be reused. + + **Details:** + + .. ts:def:: AddIncomingResponse + + interface AddIncomingResponse { + // Timestamp that indicates when the wire transfer will be executed. + // In cases where the wire transfer gateway is unable to know when + // the wire transfer will be executed, the time at which the request + // has been received and stored will be returned. + // The purpose of this field is for debugging (humans trying to find + // the transaction) as well as for taxation (determining which + // time period a transaction belongs to). + timestamp: Timestamp; + + // Opaque ID of the wire transfer initiation performed by the bank. + // It is different from the /history endpoints row_id. + row_id: SafeUint64; + } diff --git a/core/bank-wire/post-admin-add-kycauth.rst b/core/bank-wire/post-admin-add-kycauth.rst @@ -0,0 +1,35 @@ +.. http:post:: /admin/add-kycauth + + Simulate a transfer from a customer to the exchange. This API is *not* + idempotent since it's only used in testing. + + **Request:** + + .. ts:def:: AddKycauthRequest + + interface AddKycauthRequest { + // Amount to transfer. + amount: Amount; + + // Account public key that is included in the wire transfer details + // to associate this key with the originating bank account. + account_pub: EddsaPublicKey; + + // Account (as full payto URI) that makes the wire transfer to the exchange. + // Usually this account must be created by the test harness before this + // API is used. An exception is the "fakebank", where any debit account + // can be specified, as it is automatically created. + debit_account: string; + } + + **Response:** + + :http:statuscode:`200 OK`: + The request has been correctly handled, so the funds have been transferred to + the recipient's account. The body is a `AddIncomingResponse`. + :http:statuscode:`400 Bad request`: + The request is malformed. The bank replies with an `ErrorDetail` object. + :http:statuscode:`401 Unauthorized`: + Authentication failed, likely the credentials are wrong. + :http:statuscode:`404 Not found`: + The endpoint is wrong or the user name is unknown. The bank replies with an `ErrorDetail` object. diff --git a/core/bank-wire/post-admin-add-mapped.rst b/core/bank-wire/post-admin-add-mapped.rst @@ -0,0 +1,38 @@ +.. http:post:: /admin/add-mapped + + Simulate a transfer from a customer to the exchange. This API is *not* + idempotent since it's only used in testing. + + Since protocol **v5**. + + **Request:** + + .. ts:def:: AddMappedRequest + + interface AddMappedRequest { + // Amount to transfer. + amount: Amount; + + // Authorization public key used for registration. + authorization_pub: EddsaPublicKey; + + // Account (as full payto URI) that makes the wire transfer to the exchange. + // Usually this account must be created by the test harness before this + // API is used. An exception is the "fakebank", where any debit account + // can be specified, as it is automatically created. + debit_account: string; + } + + **Response:** + + :http:statuscode:`200 OK`: + The request has been correctly handled, so the funds have been transferred to + the recipient's account. The body is a `AddIncomingResponse`. + :http:statuscode:`400 Bad request`: + The request is malformed. The bank replies with an `ErrorDetail` object. + :http:statuscode:`401 Unauthorized`: + Authentication failed, likely the credentials are wrong. + :http:statuscode:`404 Not found`: + The endpoint is wrong or the user name is unknown. The bank replies with an `ErrorDetail` object. + :http:statuscode:`409 Conflict`: + The 'authorization_pub' argument is unknown or have already been used for a non recurrent transfer. diff --git a/core/bank-wire/post-transfer.rst b/core/bank-wire/post-transfer.rst @@ -0,0 +1,76 @@ +.. http:post:: /transfer + + Initiate a new wire transfer from the exchange's bank account, typically to a + merchant. + + The exchange's bank account is not included in the request, but instead + derived from the username in the ``Authorization`` header and/or the request + base URL. + + To make the API idempotent, the client must include a nonce. Requests with + the same nonce are rejected unless the request is the same. + + **Request:** + + .. ts:def:: TransferRequest + + interface TransferRequest { + // Nonce to make the request idempotent. Requests with the same + // ``request_uid`` that differs in any of the other fields + // are rejected. + request_uid: HashCode; + + // Amount to transfer. + amount: Amount; + + // Base URL of the exchange. Shall be included by the bank gateway + // in the appropriate section of the wire transfer details. + exchange_base_url: string; + + // Optional additional metadata to be stored in the transaction. + // Must match [a-zA-Z0-9-.:]{1, 40} + // @since **v5** + metadata?: string; + + // Wire transfer identifier chosen by the exchange, + // used by the merchant to identify the Taler order(s) + // associated with this wire transfer. + wtid: ShortHashCode; + + // The recipient's account identifier as a full payto URI. + credit_account: string; + } + + **Response:** + + :http:statuscode:`200 OK`: + The request has been correctly handled, so the funds have been transferred to + the recipient's account. The body is a `TransferResponse`. + :http:statuscode:`400 Bad request`: + Request malformed. The bank replies with an `ErrorDetail` object. + :http:statuscode:`401 Unauthorized`: + Authentication failed, likely the credentials are wrong. + :http:statuscode:`404 Not found`: + The endpoint is wrong or the user name is unknown. The bank replies with an `ErrorDetail` object. + :http:statuscode:`409 Conflict`: + * ``TALER_EC_BANK_TRANSFER_REQUEST_UID_REUSED``: an operation with the same ``request_uid`` but different details has been submitted before. + * ``TALER_EC_BANK_TRANSFER_WTID_REUSED``: an operation with the same ``wtid`` but a different ``request_uid`` has been submitted before. + + **Details:** + + .. ts:def:: TransferResponse + + interface TransferResponse { + // Timestamp that indicates when the wire transfer will be executed. + // In cases where the wire transfer gateway is unable to know when + // the wire transfer will be executed, the time at which the request + // has been received and stored will be returned. + // The purpose of this field is for debugging (humans trying to find + // the transaction) as well as for taxation (determining which + // time period a transaction belongs to). + timestamp: Timestamp; + + // Opaque ID of the wire transfer initiation performed by the bank. + // It is different from the /history endpoints row_id. + row_id: SafeUint64; + } diff --git a/core/challenger/get-authorize-NONCE.rst b/core/challenger/get-authorize-NONCE.rst @@ -0,0 +1 @@ +.. http:get:: /authorize/$NONCE diff --git a/core/challenger/get-config.rst b/core/challenger/get-config.rst @@ -0,0 +1,49 @@ +.. http:get:: /config + + Obtain the key configuration settings of the storage service. + + **Response:** + + :http:statuscode:`200 OK`: + Response is a `ChallengerConfigurationResponse`. + + .. ts:def:: ChallengerConfigurationResponse + + interface ChallengerConfigurationResponse { + // Name of the service + name: "challenger"; + + // libtool-style representation of the Challenger protocol version, see + // https://www.gnu.org/software/libtool/manual/html_node/Versioning.html#Versioning + // The format is "current:revision:age". + version: string; + + // URN of the implementation (needed to interpret 'revision' in version). + // @since v0, may become mandatory in the future. + implementation?: string; + + // @since **v2**. + // Object; map of keys (names of the fields of the address + // to be entered by the user) to objects with a "regex" (string) + // containing an extended Posix regular expression for allowed + // address field values, and a "hint"/"hint_i18n" giving a + // human-readable explanation to display if the value entered + // by the user does not match the regex. Keys that are not mapped + // to such an object have no restriction on the value provided by + // the user. See "ADDRESS_RESTRICTIONS" in the challenger configuration. + restrictions: Object; + + // @since **v6** + // Defines the set of fields asked to the user. + // The field names are registered via GANA at + // https://git.taler.net/gana.git/tree/gnu-taler-form-attributes + // email: CONTACT_EMAIL + // phone: CONTACT_PHONE + // postal: CONTACT_NAME, ADDRESS_LINES, ADDRESS_COUNTRY + // postal-ch: CONTACT_NAME, ADDRESS_LINES + address_type: "email" | "phone" | "postal" | "postal-ch"; + + // Hint to show in the address bar for the user as an example for + // the format of the address. + address_hint: string; + } diff --git a/core/challenger/get-info.rst b/core/challenger/get-info.rst @@ -0,0 +1,47 @@ +.. http:get:: /info + + This userinfo endpoint of the OAuth 2.0 specification. + This endpoint is used by the client to obtain the user's validated address. + + **Request:** + + Must include the token returned to the client from the ``/token`` endpoint + as a ``Bearer`` token in an ``Authorization`` header. + + **Response:** + + :http:statuscode:`200 OK`: + The body contains the address as a `ChallengerInfoResponse`. + :http:statuscode:`403 Forbidden`: + The bearer token is missing or invalid (malformed). + :http:statuscode:`404 Not found`: + The bearer token is invalid (includes unknown or expired). + Returned with ``TALER_EC_CHALLENGER_GRANT_UNKNOWN``. + :http:statuscode:`500 Internal Server Error`: + The challenger service encountered an internal error, + typically a database failure. Usually returned with + ``TALER_EC_GENERIC_DB_FETCH_FAILED``. + + **Details::** + + .. ts:def:: ChallengerInfoResponse + + interface ChallengerInfoResponse { + + // Unique ID of the record within Challenger + // (identifies the rowid of the token). + id: Integer; + + // Address that was validated. + // Key-value pairs, details depend on the + // address_type. + address: Object; + + // Type of the address. + address_type: string; + + // How long do we consider the address to be + // valid for this user. + expires: Timestamp; + + } diff --git a/core/challenger/post-authorize-NONCE.rst b/core/challenger/post-authorize-NONCE.rst @@ -0,0 +1,84 @@ +.. http:post:: /authorize/$NONCE + + This is the "authorization" endpoint of the OAuth 2.0 protocol. This + endpoint is used by the user-agent. It will return a form to enter the + address. + + The NONCE is a unique value identifying the challenge, should be shown to + the user so that they can recognize it when they receive the TAN code. + + Note that both for GET and POST requests the request arguments must + be given in the URL and the body should be empty. We currently do NOT + support using x-www-form-urlencoded arguments in the body, even for + a POST. + + **Request:** + + :query response_type: Must be ``code`` + :query client_id: Identifier of the client. + :query redirect_uri: URI-encoded redirection URI to use upon authorization. + :query state: Arbitrary client state to associate with the request. + :query scope: Not supported, any value is accepted. + :query code_challenge: A string to enhance security using PKCE (available since **v3**). + :query code_challenge_method: The method used for the code_challenge. Options are S256 (SHA-256) or plain (available since **v3**). + + **Response:** + + :http:statuscode:`200 OK`: + The the response is + a `ChallengeStatus`. Since protocol **v1**. + :http:statuscode:`302 Found`: + Returned when the client explicitly accepts ``text/html`` + returning a redirection to the WebUI. + Since protocol **v1**. + :http:statuscode:`400 Bad Request`: + The request does not follow the spec. + The response will include error + code, hint and detail. Since protocol **v1**. + :http:statuscode:`404 Not found`: + The service is unaware of a matching challenge. + The response will include error + code, hint and detail. Since protocol **v1**. + :http:statuscode:`406 Not Acceptable`: + The client ask for "text/html" and the backend installation does + not include the required HTML templates. + :http:statuscode:`500 Internal Server Error`: + Server is not able to respond due to internal problems. + The response will include error + code, hint and detail. Since protocol **v1**. + + .. ts:def:: ChallengeStatus + + interface ChallengeStatus { + + // indicates if the given address cannot be changed anymore, the + // form should be read-only if set to true. + fix_address: boolean; + + // form values from the previous submission if available, details depend + // on the ``ADDRESS_TYPE``, should be used to pre-populate the form + last_address?: Object; + + // is the challenge already solved? + solved: boolean; + + // number of times the address can still be changed, may or may not be + // shown to the user + changes_left: Integer; + + // when we would re-transmit the challenge the next + // time (at the earliest) if requested by the user + // only present if challenge already created + // @since **v2** + retransmission_time: Timestamp; + + // how many times might the PIN still be retransmitted + // only present if challenge already created + // @since **v2** + pin_transmissions_left?: Integer; + + // how many times might the user still try entering the PIN code + // only present if challenge already created + // @since **v2** + auth_attempts_left?: Integer; + } diff --git a/core/challenger/post-challenge-NONCE.rst b/core/challenger/post-challenge-NONCE.rst @@ -0,0 +1,93 @@ +.. http:post:: /challenge/$NONCE + + This endpoint is used by the user-agent to submit the address to which a + challenge should be sent by the challenger service. + + **Request:** + + Body should use the mime-type "application/x-www-form-urlencoded". + The posted form data must contain an object that follow the restrictions + defined in :ref:`config <challenger-config>`. + + **Response:** + + :http:statuscode:`200 OK`: + The response is `ChallengeResponse`. Since protocol **v2**. + :http:statuscode:`400 Bad Request`: + The request does not follow the spec. + The response will include error + code, hint and detail. Since protocol **v1**. + :http:statuscode:`403 Forbidden`: + The address being submitted differs from the previously + submitted address but the validation process was set up + as ``read_only`` and thus the address cannot be changed. + Returned with + ``TALER_EC_CHALLENGER_CLIENT_FORBIDDEN_READ_ONLY``. + Since protocol **v4**. + :http:statuscode:`404 Not Found`: + The service is unaware of a matching challenge. + The response will include error + code, hint and detail. Since protocol **v1**. + :http:statuscode:`406 Not Acceptable`: + The client ask for "text/html" and the backend installation does + not include the required HTML templates. + :http:statuscode:`429 Too Many Requests`: + There have been too many attempts to request challenge + transmissions for this $NONCE. The user-agent should + wait and (eventually) request a fresh nonce to be set + up by the client. + Returned with ``TALER_EC_CHALLENGER_TOO_MANY_ATTEMPTS``. + Since protocol **v2**. + :http:statuscode:`500 Internal Server Error`: + Server is not able to respond due to internal problems. + The response will include error + code, hint and detail. Since protocol **v1**. + :http:statuscode:`502 Bad Gateway`: + The challenger service failed to launch or communicate with + its helper process for delivering the challenge (SMS, e-mail, + postal mail). Returned with + ``TALER_EC_CHALLENGER_HELPER_EXEC_FAILED``. + + .. ts:def:: ChallengeResponse + + // Union discriminated by the "type" field. + type ChallengeResponse = ChallengeRedirect | ChallengeCreateResponse + + .. ts:def:: ChallengeRedirect + + // @since **v2** + interface ChallengeRedirect { + // Union discriminator field. + type: "completed"; + + // challenge is completed, use should redirect here + redirect_url: string; + } + + .. ts:def:: ChallengeCreateResponse + + interface ChallengeCreateResponse { + // Union discriminator field. + type: "created" + + // how many more attempts are allowed, might be shown to the user, + // highlighting might be appropriate for low values such as 1 or 2 (the + // form will never be used if the value is zero) + attempts_left: Integer; + + // the address that is being validated, might be shown or not + address: Object; + + // true if we just retransmitted the challenge, false if we sent a + // challenge recently and thus refused to transmit it again this time; + // might make a useful hint to the user + transmitted: boolean; + + // @deprecated in **v2**, use retransmission_time + next_tx_time?: string; + + // when we would re-transmit the challenge the next + // time (at the earliest) if requested by the user + // @since **v2** + retransmission_time: Timestamp; + } diff --git a/core/challenger/post-setup-CLIENT_ID.rst b/core/challenger/post-setup-CLIENT_ID.rst @@ -0,0 +1,62 @@ +.. http:post:: /setup/$CLIENT_ID + + This endpoint is used by the client to authorize the execution of an address + validation on its behalf. An ``Authorization`` header (for now always using + a ``Bearer`` token) should be included to provide the client's credentials + to authorize access to the challenger service. This token must match the + ``client_secret`` from the registration of the client with the challenger + service (which will also be used in the later ``/token`` request). + + **Request:** + + The body can be an address in JSON encoding to pre-initialize the address to + be used by challenger for this process. If the body is absent, the user will + have to enter the full address details. The specific address format depends + on the address type. However, `ChallengeSetupRequest` defines the shared + ``read_only`` bit that has a special meaning independent of the address type: + it informs Challenger that the address should not be editable. + + Passing an address in the ``/setup`` body is supported @since protocol **v4**. + + **Response:** + + :http:statuscode:`200 OK`: + Response is a `ChallengeSetupResponse`. + :http:statuscode:`400 Bad request`: + The request is malformed. Usually returned with an + error code of ``TALER_EC_GENERIC_PARAMETER_MISSING`` or + ``TALER_EC_GENERIC_PARAMETER_MALFORMED``. + :http:statuscode:`404 Not found`: + The challenger service is unaware of a matching client. + or the credentials of the client are invalid. + Usually returned with + ``TALER_EC_CHALLENGER_GENERIC_CLIENT_UNKNOWN``. + :http:statuscode:`500 Internal server error`: + The challenger service encountered an internal error. + Usually returned with + ``TALER_EC_GENERIC_DB_FETCH_FAILED`` or + ``TALER_EC_GENERIC_DB_STORE_FAILED`` or + ``TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE``. + + **Details::** + + .. ts:def:: ChallengeSetupRequest + + interface ChallengeSetupRequest { + // If true, the given address should not be edited. + // Defaults to 'false' if not specified. + read_only?: boolean; + + // Optional, additional fields to pre-populate + // the address to be validated. + // The fields depend on the challenger type. + [x: string]: any; + } + + + .. ts:def:: ChallengeSetupResponse + + interface ChallengeSetupResponse { + // Nonce to use when constructing ``/authorize`` endpoint. + nonce: string; + } diff --git a/core/challenger/post-solve-NONCE.rst b/core/challenger/post-solve-NONCE.rst @@ -0,0 +1,84 @@ +.. http:post:: /solve/$NONCE + + Used by the user-agent to submit an answer to the challenge. If the answer + is correct, the user will be redirected to the client's redirect URI, + otherwise the user may be given another chance to complete the process. + + **Request:** + + Body should use the mime-type "application/x-www-form-urlencoded". + The posted form data must contain a "pin" field. + + **Response:** + + :http:statuscode:`200 OK`: + If the request ask for application/json the response is + a `ChallengeSolveResponse`. Since protocol **v2**. + :http:statuscode:`302 Found`: + Only possible if request didn't ask for application/json. Since protocol **v2**. + The user is redirected to the redirect URI of the client to pass the + grant to the client. The target will be the redirect URI specified + by the client (during registration and again upon ``/authorize``), + plus a ``code`` argument with the authorization code, and the + ``state`` argument from the ``/authorize`` endpoint. + :http:statuscode:`400 Bad Request`: + The request does not follow the spec. + The response will include error + code, hint and detail. Since protocol **v1**. + :http:statuscode:`403 Forbidden`: + The response is `InvalidPinResponse`. Since protocol **v1**. + :http:statuscode:`404 Not found`: + The service is unaware of a matching challenge. + The response will include error + code, hint and detail. Since protocol **v1**. + :http:statuscode:`429 Too Many Requests`: + There have been too many attempts to solve the challenge + for this address (and $NONCE). The user-agent should + either try a different address (or wait and (eventually) + request a fresh nonce to be set up by the client). + The response will include error + code, hint and detail. Since protocol **v2**. + :http:statuscode:`500 Internal Server Error`: + Server is not able to respond due to internal problems. + The response will include error + code, hint and detail. Since protocol **v1**. + + .. ts:def:: ChallengeSolveResponse + + // Union discriminated by the "type" field. + type ChallengeSolveResponse = ChallengeRedirect | InvalidPinResponse; + + .. ts:def:: InvalidPinResponse + + interface InvalidPinResponse { + // Union discriminator field. + type: "pending"; + + // numeric Taler error code, should be shown to indicate the error + // compactly for reporting to developers + code: Integer; + + // human-readable Taler error code, should be shown for the user to + // understand the error + hint: string; + + // how many times is the user still allowed to change the address; + // if 0, the user should not be shown a link to jump to the + // address entry form + addresses_left: Integer; + + // how many times might the PIN still be retransmitted + pin_transmissions_left: Integer; + + // how many times might the user still try entering the PIN code + auth_attempts_left: Integer; + + // if true, the PIN was not even evaluated as the user previously + // exhausted the number of attempts + exhausted: boolean; + + // if true, the PIN was not even evaluated as no challenge was ever + // issued (the user must have skipped the step of providing their + // address first!) + no_challenge: boolean; + } diff --git a/core/challenger/post-token.rst b/core/challenger/post-token.rst @@ -0,0 +1,76 @@ +.. http:post:: /token + + This is the token endpoint of the OAuth 2.0 specification. + This endpoint is used by the client to provide its authorization code, + demonstrating that it has the right to learn a particular user's validated + address. In return, the challenger service returns the access token. + Renewal is not supported. + + **Request:** + + The request must include an ``application/www-form-urlencoded`` body + specifying the ``client_id``, ``redirect_uri``, ``client_secret``, ``code`` + and ``grant_type``. The ``grant_type`` must be set to + ``authorization_code``. The ``redirect_uri`` must match the URI from + ``/authorize``. The ``code`` must be the authorization code that ``/solve`` + returned to the user. The ``client_id`` and ``client_secret`` must match + the usual client credentials. Since protocol **v3**, ``code_verifier`` can also be included. + + **Response:** + + Error responses follow RFC 6749, section 5.2 with an "error" field in JSON, + as well as also returning GNU Taler style error messages. + + :http:statuscode:`200 OK`: + The body will be a `ChallengerAuthResponse`. + :http:statuscode:`400 Bad Request`: + A required POST field (``grant_type``, ``client_id``, + ``client_secret``, ``code`` or ``redirect_uri``) is missing + or malformed, or ``grant_type`` is not ``authorization_code``. + Usually returned with ``TALER_EC_GENERIC_PARAMETER_MISSING`` + or ``TALER_EC_GENERIC_PARAMETER_MALFORMED``. + :http:statuscode:`401 Unauthorized`: + Authentication of the client failed. Returned (per + RFC 6749, section 5.2) when the client credentials are + invalid, when the supplied ``code`` is malformed or does + not match the validation, when the ``redirect_uri`` does + not match the one registered with the client, or when the + ``code_verifier`` does not match the saved + ``code_challenge``. Returned with + ``TALER_EC_CHALLENGER_GENERIC_CLIENT_FORBIDDEN_BAD_REDIRECT_URI``, + ``TALER_EC_CHALLENGER_CLIENT_FORBIDDEN_BAD_CODE``, + ``TALER_EC_CHALLENGER_GENERIC_VALIDATION_UNKNOWN`` or + ``TALER_EC_CHALLENGER_GRANT_UNKNOWN``. + PKCE-related rejections are since protocol **v3**. + :http:statuscode:`404 Not found`: + The service is unaware of a matching login process or client. + Returned with error codes of + ``TALER_EC_CHALLENGER_GENERIC_CLIENT_UNKOWN`` + :http:statuscode:`409 Conflict`: + A ``code`` was presented for a validation process for which + the user has not (yet) submitted any address, so the token + cannot be issued. Returned with + ``TALER_EC_CHALLENGER_MISSING_ADDRESS``. + :http:statuscode:`500 Internal Server Error`: + The challenger service encountered an internal error, + for example a database failure or a failure of the SHA-256 + or Base64 helpers used for PKCE verification. + Error codes used are: + * ``TALER_EC_CHALLENGER_GENERIC_DB_FETCH_FAILED`` + * ``TALER_EC_CHALLENGER_GENERIC_DB_STORE_FAILED`` + + **Details::** + + .. ts:def:: ChallengerAuthResponse + + interface ChallengerAuthResponse { + // Token used to authenticate access in ``/info``. + access_token: string; + + // Type of the access token. + token_type: "Bearer"; + + // Amount of time that an access token is valid (in seconds). + expires_in: Integer; + + } diff --git a/core/corebank/any-accounts-USERNAME-conversion-info-star.rst b/core/corebank/any-accounts-USERNAME-conversion-info-star.rst @@ -0,0 +1,6 @@ +.. http:any:: /accounts/$USERNAME/conversion-info/* + + User custom rates, public for accounts configured with ``is_taler_exchange=true`` else private. Since **v9** + + All endpoints under this prefix are specified + by the :doc:`GNU Taler Conversion Info API </core/api-bank-conversion-info>`. diff --git a/core/corebank/any-accounts-USERNAME-taler-revenue-star.rst b/core/corebank/any-accounts-USERNAME-taler-revenue-star.rst @@ -0,0 +1,4 @@ +.. http:any:: /accounts/$USERNAME/taler-revenue/* + + All endpoints under this prefix are specified + by the :doc:`GNU Taler Revenue API </core/api-bank-revenue>`. diff --git a/core/corebank/any-accounts-USERNAME-taler-wire-gateway-star.rst b/core/corebank/any-accounts-USERNAME-taler-wire-gateway-star.rst @@ -0,0 +1,6 @@ +.. http:any:: /accounts/$USERNAME/taler-wire-gateway/* + + All endpoints under this prefix are specified + by the :doc:`GNU Taler wire gateway API </core/api-bank-wire>`. + + The endpoints are only available for accounts configured with ``is_taler_exchange=true``. diff --git a/core/corebank/any-accounts-USERNAME-taler-wire-transfer-gateway-star.rst b/core/corebank/any-accounts-USERNAME-taler-wire-transfer-gateway-star.rst @@ -0,0 +1,8 @@ +.. http:any:: /accounts/$USERNAME/taler-wire-transfer-gateway/* + + Since **v12** + + All endpoints under this prefix are specified + by the :doc:`GNU Taler prepared transfer API </core/api-bank-transfer>`. + + The endpoints are only available for accounts configured with ``is_taler_exchange=true``. diff --git a/core/corebank/any-conversion-info-star.rst b/core/corebank/any-conversion-info-star.rst @@ -0,0 +1,6 @@ +.. http:any:: /conversion-info/* + + Global conversion rate infos. + + All endpoints under this prefix are specified + by the :doc:`GNU Taler Conversion Info API </core/api-bank-conversion-info>`. diff --git a/core/corebank/any-conversion-rate-classes-CLASS_ID-conversion-info-star.rst b/core/corebank/any-conversion-rate-classes-CLASS_ID-conversion-info-star.rst @@ -0,0 +1,6 @@ +.. http:any:: /conversion-rate-classes/$CLASS_ID/conversion-info/* + + Conversion rate conversion infos, admin only. Since **v9** + + All endpoints under this prefix are specified + by the :doc:`GNU Taler Conversion Info API </core/api-bank-conversion-info>`. diff --git a/core/corebank/any-taler-integration-star.rst b/core/corebank/any-taler-integration-star.rst @@ -0,0 +1,5 @@ +.. http:any:: /taler-integration/* + + All endpoints under this prefix are specified by the. + :doc:`GNU Taler bank integration API </core/api-bank-integration>`. + This API handles the communication with Taler wallets. diff --git a/core/corebank/any-taler-observability-star.rst b/core/corebank/any-taler-observability-star.rst @@ -0,0 +1,6 @@ +.. http:any:: /taler-observability/* + + Since **v11** + + All endpoints under this prefix are specified + by the :doc:`GNU Taler Observability API </core/api-observability>`. diff --git a/core/corebank/delete-accounts-USERNAME-token.rst b/core/corebank/delete-accounts-USERNAME-token.rst @@ -0,0 +1,14 @@ +.. http:delete:: /accounts/$USERNAME/token + + Invalidate the access token that is being used to make the request. + + **Authentication:** The client must authenticate with a valid access token. + + **Response:** + + :http:statuscode:`204 No content`: + The token have been deleted. + :http:statuscode:`401 Unauthorized`: + Invalid or missing credentials. + :http:statuscode:`403 Forbidden`: + Missing rights. diff --git a/core/corebank/delete-accounts-USERNAME-tokens-TOKEN_ID.rst b/core/corebank/delete-accounts-USERNAME-tokens-TOKEN_ID.rst @@ -0,0 +1,14 @@ +.. http:delete:: /accounts/$USERNAME/tokens/$TOKEN_ID + + Delete an access token. + + **Response:** + + :http:statuscode:`204 No content`: + The token have been deleted. + :http:statuscode:`404 Not found`: + Token ``$TOKEN_ID`` was not found. + :http:statuscode:`401 Unauthorized`: + Invalid or missing credentials. + :http:statuscode:`403 Forbidden`: + Missing rights. diff --git a/core/corebank/delete-accounts-USERNAME.rst b/core/corebank/delete-accounts-USERNAME.rst @@ -0,0 +1,21 @@ +.. http:delete:: /accounts/$USERNAME + + Delete the account whose username is ``$USERNAME``. The deletion + succeeds only if the balance is *zero*. Typically only available to + the administrator, but can be configured to allow ordinary users too. + + **Response:** + + :http:statuscode:`202 Accepted`: + 2FA is required for this operation. This returns the `ChallengeResponse` response. @since **v10** + :http:statuscode:`204 No content`: + The account was successfully deleted. + :http:statuscode:`401 Unauthorized`: + Invalid or missing credentials. + :http:statuscode:`403 Forbidden`: + Missing rights. + :http:statuscode:`404 Not found`: + The account pointed by ``$USERNAME`` was not found. + :http:statuscode:`409 Conflict`: + * ``TALER_EC_BANK_RESERVED_USERNAME_CONFLICT`` : a reserved username was attempted, like ``admin`` or ``bank``. + * ``TALER_EC_BANK_ACCOUNT_BALANCE_NOT_ZERO``: the account balance was not zero. diff --git a/core/corebank/delete-conversion-rate-classes-CLASS_ID.rst b/core/corebank/delete-conversion-rate-classes-CLASS_ID.rst @@ -0,0 +1,22 @@ +.. http:delete:: /conversion-rate-classes/{CLASS_ID} + + Delete an existing conversion rate class. + + Only available to the administrator. + + Since protocol **v9**. + + **Response:** + + :http:statuscode:`204 No Content`: + The conversion rate class request was correctly deleted. + :http:statuscode:`401 Unauthorized`: + Invalid or missing credentials. + :http:statuscode:`403 Forbidden`: + Missing rights. + :http:statuscode:`404 Not Found`: + The conversion rate class was not found. + :http:statuscode:`409 Conflict`: + * ``TODO_LINKED_ACCOUNT`` : some accounts belongs to this class. + :http:statuscode:`501 Not implemented`: + This server does not support conversion, client should check config response. diff --git a/core/corebank/get-accounts-USERNAME-cashouts-CASHOUT_ID.rst b/core/corebank/get-accounts-USERNAME-cashouts-CASHOUT_ID.rst @@ -0,0 +1,35 @@ +.. http:get:: /accounts/$USERNAME/cashouts/$CASHOUT_ID + + Returns information about the status of the ``$CASHOUT_ID`` operation. + The request is available to the administrator and the account owner. + + **Response:** + + :http:statuscode:`200 OK`: + Response is a `CashoutStatusResponse`. + :http:statuscode:`401 Unauthorized`: + Invalid or missing credentials. + :http:statuscode:`403 Forbidden`: + Missing rights. + :http:statuscode:`404 Not found`: + The cashout operation was not found. + :http:statuscode:`501 Not implemented`: + This server does not support conversion, client should check config response. + + **Details:** + + .. ts:def:: CashoutStatusResponse + + interface CashoutStatusResponse { + // Amount debited to the regional bank account. + amount_debit: Amount; + + // Amount credited to the fiat bank account. + amount_credit: Amount; + + // Transaction subject. + subject: string; + + // Time when the cashout was created. + creation_time: Timestamp; + } diff --git a/core/corebank/get-accounts-USERNAME-cashouts.rst b/core/corebank/get-accounts-USERNAME-cashouts.rst @@ -0,0 +1,42 @@ +.. http:get:: /accounts/$USERNAME/cashouts + + Returns the list of all cash-out operations for an account. + + **Request:** + + :query limit: *Optional.* + At most return the given number of results. Negative for descending by ``cashout_id``, positive for ascending by ``cashout_id``. Defaults to ``-20``. Since **v5**. + :query offset: *Optional.* + Starting ``cashout_id`` for :ref:`pagination <row-id-pagination>`. Since **v5**. + :query delta: *Optional.* + Deprecated since **v5**. Use *limit* instead. + :query start: *Optional.* + Deprecated since **v5**. Use *offset* instead. + + **Response:** + + :http:statuscode:`200 OK`: + Response is a `Cashouts`. + :http:statuscode:`204 No Content`: + No cash-out operations were found. + :http:statuscode:`401 Unauthorized`: + Invalid or missing credentials. + :http:statuscode:`403 Forbidden`: + Missing rights. + :http:statuscode:`501 Not implemented`: + This server does not support conversion, client should check config response. + + **Details:** + + .. ts:def:: Cashouts + + interface Cashouts { + // Every string represents a cash-out operation ID. + cashouts: CashoutInfo[]; + } + + .. ts:def:: CashoutInfo + + interface CashoutInfo { + cashout_id: Integer; + } diff --git a/core/corebank/get-accounts-USERNAME-tokens.rst b/core/corebank/get-accounts-USERNAME-tokens.rst @@ -0,0 +1,68 @@ +.. http:get:: /accounts/$USERNAME/tokens + + Retrieve a subset of tokens related to $USERNAME. + @since **v4** + + **Request:** + + :query limit: *Optional.* + At most return the given number of results. Negative for descending by ``token_id``, positive for ascending by ``token_id``. Defaults to ``-20``. Since **v5**. + :query offset: *Optional.* + Starting ``token_id`` for :ref:`pagination <row-id-pagination>`. Since **v5**. + :query delta: *Optional.* + Deprecated since **v5**. Use *limit* instead. + :query start: *Optional.* + Deprecated since **v5**. Use *offset* instead. + + **Response:** + + :http:statuscode:`200 OK`: + Response is a `TokenInfos`. + :http:statuscode:`204 No content`: + No tokens. + :http:statuscode:`401 Unauthorized`: + Invalid or missing credentials. + :http:statuscode:`403 Forbidden`: + Mmissing rights. + + **Details:** + + .. ts:def:: TokenInfos + + interface TokenInfos { + tokens: TokenInfo[]; + } + + .. ts:def:: TokenInfo + + interface TokenInfo { + // Time when the token was created. + creation_time: Timestamp; + + // Expiration determined by the server. + // Can be based on the token_duration + // from the request, but ultimately the + // server decides the expiration. + expiration: Timestamp; + + // Scope for the token. + scope: "readonly" | "readwrite" | "revenue" | "wiregateway"; + + // Is the token refreshable into a new token during its + // validity? + // Refreshable tokens effectively provide indefinite + // access if they are refreshed in time. + refreshable: boolean; + + // Optional token description + description?: string; + + // Time when the token was last used. + last_access: Timestamp; + + // ID identifying the token + token_id: Integer; + + // deprecated since **v9**. Use *token_id* instead. + row_id: Integer; + } diff --git a/core/corebank/get-accounts-USERNAME-transactions-TRANSACTION_ID.rst b/core/corebank/get-accounts-USERNAME-transactions-TRANSACTION_ID.rst @@ -0,0 +1,44 @@ +.. http:get:: /accounts/$USERNAME/transactions/$TRANSACTION_ID + + Retrieve the transaction whose identifier is ``TRANSACTION_ID``. + + **Response:** + + :http:statuscode:`200 OK`: + The bank responds with an `BankAccountTransactionInfo` object. + :http:statuscode:`401 Unauthorized`: + Invalid or missing credentials. + :http:statuscode:`403 Forbidden`: + Missing rights. + :http:statuscode:`404 Not found`: + The account pointed by ``$USERNAME`` was not found. + + **Details:** + + .. ts:def:: BankAccountTransactionInfo + + interface BankAccountTransactionInfo { + // Full payto URI to identify the receiver of funds. + creditor_payto_uri: string; + + // Full payto URI to identify the sender of funds. + debtor_payto_uri: string; + + // Amount received. + amount: Amount; + + // The direction of the transaction relative to $USERNAME account. + // debit: $USERNAME is the debtor + // credit: $USERNAME is the creditor + direction: "debit" | "credit"; + + // The wire transfer subjec + subject: string; + + // Transaction unique ID. Matches + // $TRANSACTION_ID from the URI. + row_id: Integer; + + // Date of the transaction. + date: Timestamp; + } diff --git a/core/corebank/get-accounts-USERNAME-transactions.rst b/core/corebank/get-accounts-USERNAME-transactions.rst @@ -0,0 +1,39 @@ +.. http:get:: /accounts/$USERNAME/transactions + + Retrieve a subset of transactions related to $USERNAME. + + **Request:** + + :query limit: *Optional.* + At most return the given number of results. Negative for descending by ``row_id``, positive for ascending by ``row_id``. Defaults to ``-20``. Since **v5**. + :query offset: *Optional.* + Starting ``row_id`` for :ref:`pagination <row-id-pagination>`. Since **v5**. + :query timeout_ms: *Optional.* + Timeout in milliseconds, for :ref:`long-polling <long-polling>`, to wait for at least one element to be shown. Only useful if *limit* is positive. Since protocol **v5**. + :query delta: *Optional.* + Deprecated since **v5**. Use *limit* instead. + :query start: *Optional.* + Deprecated since **v5**. Use *offset* instead. + :query long_poll_ms: *Optional.* + Deprecated since **v5**. Use *timeout_ms* instead. + + **Response:** + + :http:statuscode:`200 OK`: + The bank responds with an `BankAccountTransactionsResponse` object. + :http:statuscode:`204 No content`: + No transaction found. + :http:statuscode:`401 Unauthorized`: + Invalid or missing credentials. + :http:statuscode:`403 Forbidden`: + Missing rights. + :http:statuscode:`404 Not found`: + The account pointed by ``$USERNAME`` was not found. + + **Details:** + + .. ts:def:: BankAccountTransactionsResponse + + interface BankAccountTransactionsResponse { + transactions: BankAccountTransactionInfo[]; + } diff --git a/core/corebank/get-accounts-USERNAME.rst b/core/corebank/get-accounts-USERNAME.rst @@ -0,0 +1,90 @@ +.. http:get:: /accounts/$USERNAME + + Obtains information relative to the account owned by + ``$USERNAME``. The request is available to the administrator + and ``$USERNAME`` itself. + + **Response:** + + :http:statuscode:`200 OK`: + The bank responds with an `AccountData` object. + :http:statuscode:`401 Unauthorized`: + Invalid or missing credentials. + :http:statuscode:`403 Forbidden`: + Missing rights. + :http:statuscode:`404 Not found`: + The account pointed by ``$USERNAME`` was not found. + + **Details:** + + .. ts:def:: AccountData + + interface AccountData { + // Legal name of the account owner. + name: string; + + // Available balance on the account. + balance: Balance; + + // Full payto URI of the account. + payto_uri: string; + + // Number indicating the max debit allowed for the requesting user. + debit_threshold: Amount; + + // Custom minimum cashout amount for this account. + // If null or absent, the global conversion fee is used. + // @since **v6** + // @deprecated in **v9**, use conversion_rate_class_id instead + min_cashout?: Amount; + + // Addresses where to send the TAN for transactions. + // Currently only used for cashouts. + // If missing, cashouts will fail. + // In the future, might be used for other transactions + // as well. + contact_data?: ChallengeContactData; + + // Full 'payto' URI of a fiat bank account where to send cashouts with + // ``name`` as the 'receiver-name'. + // This field is optional + // because not all the accounts are required to participate + // in the merchants' circuit. One example is the exchange: + // that never cashouts. Registering these accounts can + // be done via the access API. + cashout_payto_uri?: string; + + // Is this account visible to anyone? + is_public: boolean; + + // Is this a taler exchange account? + is_taler_exchange: boolean; + + // Is the account locked. + // Defaults to false. + // @deprecated since **v7** + is_locked?: boolean; + + // @deprecated in **v10** + // Is 2FA enabled and what channel is used for challenges? + tan_channel?: TanChannel; + + // Is 2FA enabled and what channels are used for challenges? + // @since **v10** + tan_channels?: TanChannel[]; + + // Current status of the account + // active: the account can be used + // locked: the account can be used but cannot create new tokens + // @since **v7** + // deleted: the account has been deleted but is retained for compliance + // reasons, only the administrator can access it + // Defaults to 'active' is missing + // @since **v4**, will become mandatory in the next version. + status?: "active" | "locked" | "deleted"; + + // Conversion rate class of the user + // Only present if conversion is activated on the server + // @since **v9** + conversion_rate_class_id?: Integer; + } diff --git a/core/corebank/get-accounts.rst b/core/corebank/get-accounts.rst @@ -0,0 +1,111 @@ +.. http:get:: /accounts + + Obtains a list of the accounts registered at the bank. + It returns only the information that this API handles, without + any balance or transactions list. + This request is only available to the administrator. + + **Request:** + + :query limit: *Optional.* + At most return the given number of results. Negative for descending by ``row_id``, positive for ascending by ``row_id``. Defaults to ``-20``. Since **v5**. + :query offset: *Optional.* + Starting ``row_id`` for :ref:`pagination <row-id-pagination>`. Since **v5**. + :query filter_name: *Optional.* + Pattern to filter on the account's legal name. Given + the filter 'foo', all the accounts will **contain** + 'foo' in their legal name. Without this option, + all the existing accounts are returned. + :query conversion_rate_class_id: *Optional.* + Id of a conversion rate class. Given the filter '1', the accounts will be part of the conversion rate class 1. Given the filter '0', will have no conversion rate class. Without this option all the existing accounts are returned. Since **v9**. + :query delta: *Optional.* + Deprecated since **v5**. Use *limit* instead. + :query start: *Optional.* + Deprecated since **v5**. Use *offset* instead. + + **Response:** + + :http:statuscode:`200 OK`: + At least one account was found. + The server responds with a `ListBankAccountsResponse` object. + :http:statuscode:`204 No Content`: + No accounts were found for the given request. + :http:statuscode:`401 Unauthorized`: + Invalid or missing credentials. + :http:statuscode:`403 Forbidden`: + Missing rights. + + **Details:** + + .. ts:def:: ListBankAccountsResponse + + interface ListBankAccountsResponse { + accounts: AccountMinimalData[]; + } + + .. ts:def:: Balance + + interface Balance { + amount: Amount; + credit_debit_indicator: "credit" | "debit"; + } + + .. ts:def:: AccountMinimalData + + interface AccountMinimalData { + // Username of the account + username: string; + + // Legal name of the account owner. + name: string; + + // Full payto URI of this bank account. + payto_uri: string; + + // Current balance of the account + balance: Balance; + + // Number indicating the max debit allowed for the requesting user. + debit_threshold: Amount; + + // Custom minimum cashout amount for this account. + // If null or absent, the global conversion fee is used. + // @since **v6** + // @deprecated in **v9**, use conversion_rate_class_id instead + min_cashout?: Amount; + + // Is this account visible to anyone? + is_public: boolean; + + // Is this a taler exchange account? + is_taler_exchange: boolean; + + // Is the account locked. + // Defaults to false. + // @deprecated since **v7** + is_locked?: boolean; + + // Opaque unique ID used for pagination. + // @since **v4**, will become mandatory in the next version. + row_id?: Integer; + + // Current status of the account + // active: the account can be used + // locked: the account can be used but cannot create new tokens + // @since **v7** + // deleted: the account has been deleted but is retained for compliance + // reasons, only the administrator can access it + // Defaults to 'active' is missing + // @since **v4**, will become mandatory in the next version. + status?: "active" | "locked" | "deleted"; + + // Conversion rate class of the user + // Only present if conversion is activated on the server + // @since **v9** + conversion_rate_class_id?: Integer; + + // Conversion rate available to the user + // Only present if conversion is activated on the server + // @since **v9** + conversion_rate?: ConversionRate; + } diff --git a/core/corebank/get-cashouts.rst b/core/corebank/get-cashouts.rst @@ -0,0 +1,49 @@ +.. http:get:: /cashouts + + Returns the list of all cash-out operations for **all** accounts. + + Can only be used by the administrators. + + **Request:** + + :query limit: *Optional.* + At most return the given number of results. Negative for descending by ``cashout_id``, positive for ascending by ``cashout_id``. Defaults to ``-20``. Since **v5**. + :query offset: *Optional.* + Starting ``cashout_id`` for :ref:`pagination <row-id-pagination>`. Since **v5**. + :query delta: *Optional.* + Deprecated since **v5**. Use *limit* instead. + :query start: *Optional.* + Deprecated since **v5**. Use *offset* instead. + + .. note:: + + We might want to add a filter in the future to only + query pending cashout operations. + + **Response:** + + :http:statuscode:`200 OK`: + Response is a `GlobalCashouts`. + :http:statuscode:`204 No Content`: + No cash-out operations were found. + :http:statuscode:`401 Unauthorized`: + Invalid or missing credentials. + :http:statuscode:`403 Forbidden`: + Missing rights. + :http:statuscode:`501 Not implemented`: + This server does not support conversion, client should check config response. + + **Details:** + + .. ts:def:: GlobalCashouts + + interface GlobalCashouts { + cashouts: GlobalCashoutInfo[]; + } + + .. ts:def:: GlobalCashoutInfo + + interface GlobalCashoutInfo { + cashout_id: Integer; + username: string; + } diff --git a/core/corebank/get-config.rst b/core/corebank/get-config.rst @@ -0,0 +1,82 @@ +.. http:get:: /config + + Return the protocol version and configuration information about the bank. + This specification corresponds to ``current`` protocol being version **v12**. + + **Response:** + + :http:statuscode:`200 OK`: + Response is a `Config`. + + **Details:** + + .. ts:def:: Config + + interface Config { + // Name of the API. + name: "taler-corebank"; + + // libtool-style representation of the Bank protocol version, see + // https://www.gnu.org/software/libtool/manual/html_node/Versioning.html#Versioning + // The format is "current:revision:age". + version: string; + + // Bank display name to be used in user interfaces. + // For consistency use "Taler Bank" if missing. + // @since **v4**, will become mandatory in the next version. + bank_name?: string; + + // Advertised base URL to use when you sharing an URL with another + // program. + // @since **v4**. + base_url?: string; + + // If 'true' the server provides local currency conversion support + // If 'false' some parts of the API are not supported and return 501 + allow_conversion: boolean; + + // If 'true' anyone can register + // If 'false' only admin can + allow_registrations: boolean; + + // If 'true' account can delete themselves + // If 'false' only admin can delete accounts + allow_deletions: boolean; + + // If 'true' anyone can edit their name + // If 'false' only admin can + allow_edit_name: boolean; + + // If 'true' anyone can edit their cashout account + // If 'false' only admin can + allow_edit_cashout_payto_uri: boolean; + + // Default debt limit for newly created accounts + default_debit_threshold: Amount; + + // Currency used by this bank. + currency: string; + + // How the bank SPA should render this currency. + currency_specification: CurrencySpecification; + + // TAN channels supported by the server + supported_tan_channels: TanChannel[]; + + // Wire transfer type supported by the bank. + // Defaults to 'iban' is missing + // @since **v4**, will become mandatory in the next version. + wire_type?: string; + + // Wire transfer execution fees. Only applies to bank transactions and withdrawals. + // @since **v4**, will become mandatory in the next version. + wire_transfer_fees?: Amount; + + // Minimum wire transfer amount allowed. Only applies to bank transactions and withdrawals. + // @since **v4**, will become mandatory in the next version. + min_wire_transfer_amount?: Amount; + + // Maximum wire transfer amount allowed. Only applies to bank transactions and withdrawals. + // @since **v4**, will become mandatory in the next version. + max_wire_transfer_amount?: Amount; + } diff --git a/core/corebank/get-conversion-rate-classes-CLASS_ID.rst b/core/corebank/get-conversion-rate-classes-CLASS_ID.rst @@ -0,0 +1,62 @@ +.. http:get:: /conversion-rate-classes/{CLASS_ID} + + Get an existing conversion rate class. + + Only available to the administrator. + + Since protocol **v9**. + + **Response:** + + :http:statuscode:`200 OK`: + Response is a `ConversionRateClass`. + :http:statuscode:`401 Unauthorized`: + Invalid or missing credentials. + :http:statuscode:`403 Forbidden`: + Missing rights. + :http:statuscode:`404 Not Found`: + The conversion rate class was not found. + :http:statuscode:`501 Not implemented`: + This server does not support conversion, client should check config response. + + **Details:** + + .. ts:def:: ConversionRateClassResponse + + interface ConversionRateClass { + // The name of this class + name: string; + + // A description of the class + description?: string; + + // Class unique ID + conversion_rate_class_id: Integer; + + // Number of users affected to this class + num_users: Integer; + + // Minimum fiat amount authorised for cashin before conversion + cashin_min_amount?: Amount; + + // Exchange rate to buy regional currency from fiat + cashin_ratio?: DecimalNumber; + + // Regional amount fee to subtract after applying the cashin ratio. + cashin_fee?: Amount; + + // Rounding mode used during cashin conversion + cashin_rounding_mode?: "zero" | "up" | "nearest"; + + // Minimum regional amount authorised for cashout before conversion + cashout_min_amount?: Amount; + + // Exchange rate to sell regional currency for fiat + cashout_ratio?: DecimalNumber; + + // Fiat amount fee to subtract after applying the cashout ratio. + cashout_fee?: Amount; + + // Rounding mode used during cashout conversion + cashout_rounding_mode?: "zero" | "up" | "nearest"; + } diff --git a/core/corebank/get-conversion-rate-classes.rst b/core/corebank/get-conversion-rate-classes.rst @@ -0,0 +1,40 @@ +.. http:get:: /conversion-rate-classes + + Returns the list of all conversion rate classes. + + Only available to the administrator. + + Since protocol **v9**. + + **Request:** + + :query limit: *Optional.* + At most return the given number of results. Negative for descending by ``conversion_rate_class_id``, positive for ascending by ``conversion_rate_class_id``. Defaults to ``-20``. + :query offset: *Optional.* + Starting ``conversion_rate_class_id`` for :ref:`pagination <row-id-pagination>`. + :query filter_name: *Optional.* + Pattern to filter on the class name. Given + the filter 'foo', all the classes will **contain** + 'foo' in their name. Without this option, + all the existing classes are returned. + + **Response:** + + :http:statuscode:`200 OK`: + Response is a `ConversionRateClasses`. + :http:statuscode:`401 Unauthorized`: + Invalid or missing credentials. + :http:statuscode:`403 Forbidden`: + Missing rights. + :http:statuscode:`404 Not Found`: + The conversion rate class was not found. + :http:statuscode:`501 Not implemented`: + This server does not support conversion, client should check config response. + + **Details:** + + .. ts:def:: ConversionRateClasses + + interface ConversionRateClasses { + classes: ConversionRateClass[]; + } diff --git a/core/corebank/get-monitor.rst b/core/corebank/get-monitor.rst @@ -0,0 +1,127 @@ +.. http:get:: /monitor + + When the bank provides conversion between the local currency and an + external one, this call lets the bank administrator monitor the cashin + and cashout operations that were made from and to the external currency. + It shows as well figures related to internal payments made by a Taler + exchange component to internal bank accounts. Timeframes are in UTC. + + **Request:** + + :query timeframe: *Optional*. + This parameter admits one of the following values. Defaults to 'hour'. + + * hour + * day + * month + * year + + :query date_s: *Optional*. + Non-negative date in seconds after the UNIX Epoch. Defaults to current time. + @since **v4** + + :query which: *Optional*. + This parameter points at a particular element of the *timeframe* parameter. + Following are the admitted values for each one. + Defaults to the last snapshot taken of the *timeframe* parameter. + @deprecated since **v4** + + * hour: from 00 to 23 + * day: from 1 to the last day of the current month. + * month: from 1 to 12 + * year: Gregorian year in the YYYY format. + + **Response:** + + :http:statuscode:`200 OK`: + The bank responds with `MonitorResponse`. + :http:statuscode:`400 Bad Request`: + This error may indicate that the *which* parameter is not appropriate for the selected *timeframe*. For example, timeframe=month and which=20 would result in this error. + :http:statuscode:`401 Unauthorized`: + Invalid or missing credentials. + :http:statuscode:`403 Forbidden`: + Missing rights. + + **Details:** + + .. note:: + + API consumers may combine the values in the response with other + factors to serve different views to their users. + + .. ts:def:: MonitorResponse + + // Union discriminated by the "type" field. + type MonitorResponse = + | MonitorNoConversion + | MonitorWithConversion; + + .. ts:def:: MonitorNoConversion + + // Monitoring stats when conversion is not supported + interface MonitorNoConversion { + type: "no-conversions"; + + // How many payments were made to a Taler exchange by another + // bank account. + talerInCount: Integer; + + // Overall volume that has been paid to a Taler + // exchange by another bank account. + talerInVolume: Amount; + + // How many payments were made by a Taler exchange to another + // bank account. + talerOutCount: Integer; + + // Overall volume that has been paid by a Taler + // exchange to another bank account. + talerOutVolume: Amount; + } + + .. ts:def:: MonitorWithConversion + + // Monitoring stats when conversion is supported + interface MonitorWithConversion { + type: "with-conversions"; + + // How many cashin operations were confirmed by a + // wallet owner. Note: wallet owners + // are NOT required to be customers of the libeufin-bank. + cashinCount: Integer; + + // Overall regional currency that has been paid by the regional admin account + // to regional bank accounts to fulfill all the confirmed cashin operations. + cashinRegionalVolume: Amount; + + // Overall fiat currency that has been paid to the fiat admin account + // by fiat bank accounts to fulfill all the confirmed cashin operations. + cashinFiatVolume: Amount; + + // How many cashout operations were confirmed. + cashoutCount: Integer; + + // Overall regional currency that has been paid to the regional admin account + // by fiat bank accounts to fulfill all the confirmed cashout operations. + cashoutRegionalVolume: Amount; + + // Overall fiat currency that has been paid by the fiat admin account + // to fiat bank accounts to fulfill all the confirmed cashout operations. + cashoutFiatVolume: Amount; + + // How many payments were made to a Taler exchange by another + // bank account. + talerInCount: Integer; + + // Overall volume that has been paid to a Taler + // exchange by another bank account. + talerInVolume: Amount; + + // How many payments were made by a Taler exchange to another + // bank account. + talerOutCount: Integer; + + // Overall volume that has been paid by a Taler + // exchange to another bank account. + talerOutVolume: Amount; + } diff --git a/core/corebank/get-public-accounts.rst b/core/corebank/get-public-accounts.rst @@ -0,0 +1,55 @@ +.. http:get:: /public-accounts + + Show those accounts whose histories are publicly visible. For example, + accounts from donation receivers. As such, this request is unauthenticated. + + **Request:** + + :query limit: *Optional.* + At most return the given number of results. Negative for descending by ``row_id``, positive for ascending by ``row_id``. Defaults to ``-20``. Since **v5**. + :query offset: *Optional.* + Starting ``row_id`` for :ref:`pagination <row-id-pagination>`. Since **v5**. + :query filter_name: *Optional.* + Pattern to filter on the account's legal name. Given + the filter 'foo', all the results will **contain** + 'foo' in their legal name. Without this option, + all the existing accounts are returned. + :query delta: *Optional.* + Deprecated since **v5**. Use *limit* instead. + :query start: *Optional.* + Deprecated since **v5**. Use *offset* instead. + + **Response:** + + :http:statuscode:`200 OK`: + Response is a `PublicAccountsResponse`. + :http:statuscode:`204 No content`: + No public account. + + **Details:** + + .. ts:def:: PublicAccountsResponse + + interface PublicAccountsResponse { + public_accounts: PublicAccount[]; + } + + .. ts:def:: PublicAccount + + interface PublicAccount { + // Username of the account + username: string; + + // Full payto URI of this bank account. + payto_uri: string; + + // Current balance of the account + balance: Balance; + + // Is this a taler exchange account? + is_taler_exchange: boolean; + + // Opaque unique ID used for pagination. + // @since **v4**, will become mandatory in the next version. + row_id?: Integer; + } diff --git a/core/corebank/get-withdrawals-WITHDRAWAL_ID.rst b/core/corebank/get-withdrawals-WITHDRAWAL_ID.rst @@ -0,0 +1,65 @@ +.. http:get:: /withdrawals/$WITHDRAWAL_ID + + Retrieve public information about ``WITHDRAWAL_ID`` withdrawal operation. + Does not require further authentication as knowledge of ``WITHDRAWAL_ID`` + serves as an authenticator. + + **Request:** + + :query old_state: + *Optional.* Defaults to "pending". + :query timeout_ms: *Optional.* + Timeout in milliseconds, for :ref:`long-polling <long-polling>`, to wait for the operation state to be different from *old_state*. Since **v5**. + :query long_poll_ms: *Optional.* + Deprecated since **v5.** Use *timeout_ms* instead. + + **Response:** + + :http:statuscode:`200 Ok`: + The bank responds with an `WithdrawalPublicInfo` object. + :http:statuscode:`404 Not found`: + The operation was not found. + + **Details:** + + .. ts:def:: WithdrawalPublicInfo + + interface WithdrawalPublicInfo { + // Current status of the operation + // pending: the operation is pending parameters selection (exchange and reserve public key) + // selected: the operations has been selected and is pending confirmation + // aborted: the operation has been aborted + // confirmed: the transfer has been confirmed and registered by the bank + status: "pending" | "selected" | "aborted" | "confirmed"; + + // Amount that will be withdrawn with this operation + // (raw amount without fee considerations). Only + // given once the amount is fixed and cannot be changed. + // Optional since **v6**. + amount?: Amount; + + // Suggestion for the amount to be withdrawn with this + // operation. Given if a suggestion was made but the + // user may still change the amount. + // Optional since **v6**. + suggested_amount?: Amount; + + // If true, the wallet must not allow the user to + // specify an amount to withdraw and to not provide + // any amount when registering with the withdrawal + // operation. The amount to withdraw will be set + // by the final ``/withdrawals/$WITHDRAWAL_ID/confirm`` step. + // @since **v8** + no_amount_to_wallet?: boolean; + + // Account username + username: string; + + // Reserve public key selected by the exchange, + // only non-null if ``status`` is ``selected`` or ``confirmed``. + selected_reserve_pub?: string; + + // Exchange account selected by the wallet + // only non-null if ``status`` is ``selected`` or ``confirmed``. + selected_exchange_account?: string; + } diff --git a/core/corebank/patch-accounts-USERNAME-auth.rst b/core/corebank/patch-accounts-USERNAME-auth.rst @@ -0,0 +1,34 @@ +.. http:patch:: /accounts/$USERNAME/auth + + Allows changing the account's password. + + + **Request:** + + .. ts:def:: AccountPasswordChange + + interface AccountPasswordChange { + // Old password. If present it need to match the current + // password before updating. + old_password?: string; + // New password. + new_password: string; + } + + **Response:** + + :http:statuscode:`202 Accepted`: + 2FA is required for this operation. This returns the `ChallengeResponse` response. @since **v10** + :http:statuscode:`204 No content`: + Operation successful. + :http:statuscode:`404 Not found`: + The account pointed by ``$USERNAME`` was not found. + :http:statuscode:`401 Unauthorized`: + Invalid or missing credentials. + :http:statuscode:`403 Forbidden`: + Missing rights. + :http:statuscode:`409 Conflict`: + * ``TALER_EC_BANK_NON_ADMIN_PATCH_MISSING_OLD_PASSWORD``: a non-admin user has tried to change their password whihout providing the current one. + * ``TALER_EC_BANK_PATCH_BAD_OLD_PASSWORD`` : provided old password does not match current password. + * ``TALER_EC_BANK_PASSWORD_TOO_SHORT``: new password is shorter than 8 characters. + * ``TALER_EC_BANK_PASSWORD_TOO_LONG``: new password is longer than 64 characters. diff --git a/core/corebank/patch-accounts-USERNAME.rst b/core/corebank/patch-accounts-USERNAME.rst @@ -0,0 +1,71 @@ +.. http:patch:: /accounts/$USERNAME + + Allows reconfiguring the account data of ``$USERNAME``. + + **Request:** + + .. ts:def:: AccountReconfiguration + + interface AccountReconfiguration { + // Addresses where to send the TAN for protected operations. + contact_data?: ChallengeContactData; + + // Payto URI of a fiat bank account. + // Payments will be sent to this bank account + // when the user wants to convert the regional currency + // back to fiat currency outside bank. + // Only admin can change this property if not allowed in config + // Sending null will disable cashout + cashout_payto_uri?: string | null; + + // If present, change the legal name associated with $username. + // Only admin can change this property if not allowed in config + name?: string; + + // Make this account visible to anyone? + is_public?: boolean; + + // If present, change the max debit allowed for this user + // Only admin can change this property. + debit_threshold?: Amount; + + // If present, set the user conversion rate class + // Only admin can set this property. + // Sending null will remove the class and switch to default class + // @since **v9** + conversion_rate_class_id?: Integer | null; + + // @deprecated in **v10** + // If present, enables 2FA and set the TAN channel used for challenges + // Sending null will disable 2FA + tan_channel?: TanChannel | null; + + // If present and not empty, enables 2FA and set the TAN channels used for challenges + // Sending null or an empty array will disable 2FA + // @since **v10** + tan_channels?: TanChannel[] | null; + + // @deprecated in **v9**, user conversion rate classes instead + min_cashout?: Amount; + } + + **Response:** + + :http:statuscode:`202 Accepted`: + 2FA is required for this operation. This returns the `ChallengeResponse` response. @since **v10** + :http:statuscode:`204 No content`: + Operation successful. + :http:statuscode:`401 Unauthorized`: + Invalid or missing credentials. + :http:statuscode:`403 Forbidden`: + Missing rights. + :http:statuscode:`404 Not found`: + The account pointed by ``$USERNAME`` was not found. + :http:statuscode:`409 Conflict`: + * ``TALER_EC_BANK_NON_ADMIN_PATCH_LEGAL_NAME`` : a non-admin user has tried to change their legal name. + * ``TALER_EC_BANK_NON_ADMIN_PATCH_CASHOUT`` : a non-admin user has tried to change their cashout account. + * ``TALER_EC_BANK_NON_ADMIN_PATCH_DEBT_LIMIT`` : a non-admin user has tried to change their debt limit. + * ``TALER_EC_BANK_NON_ADMIN_SET_CONVERSION_RATE_CLASS`` : a non-admin user has tried to create an account with a conversion rate class. Since **v9** + * ``TALER_EC_BANK_TAN_CHANNEL_NOT_SUPPORTED`` : ``tan_channel`` or one of ``tan_channels`` is not supported, check bank config to find supported ones. + * ``TALER_EC_BANK_MISSING_TAN_INFO`` : the user did not share any contact data where to send the TAN via ``tan_channel`` or one of ``tan_channels``. + * ``TALER_EC_BANK_CONVERSION_RATE_CLASS_UNKNOWN`` : no conversion rate class found for this id. Since **v9** diff --git a/core/corebank/patch-conversion-rate-classes-CLASS_ID.rst b/core/corebank/patch-conversion-rate-classes-CLASS_ID.rst @@ -0,0 +1,26 @@ +.. http:patch:: /conversion-rate-classes/{CLASS_ID} + + Edit an existing conversion rate class. + + Only available to the administrator. + + Since protocol **v9**. + + **Request:** + + `ConversionRateClassInput` + + **Response:** + + :http:statuscode:`204 No Content`: + The conversion rate class request was correctly edited. + :http:statuscode:`401 Unauthorized`: + Invalid or missing credentials. + :http:statuscode:`403 Forbidden`: + Missing rights. + :http:statuscode:`404 Not Found`: + The conversion rate class was not found. + :http:statuscode:`409 Conflict`: + * ``TALER_EC_BANK_NAME_REUSE`` : name already used. + :http:statuscode:`501 Not implemented`: + This server does not support conversion, client should check config response. diff --git a/core/corebank/post-accounts-USERNAME-cashouts.rst b/core/corebank/post-accounts-USERNAME-cashouts.rst @@ -0,0 +1,78 @@ +.. http:post:: /accounts/$USERNAME/cashouts + + Initiates a conversion to fiat currency. The fiat + bank account to be + credited is the one specified at registration time via the + *cashout_payto_uri* parameter. The regional bank account + is specified via ``$USERNAME``. + + .. note:: + + Consult the `cashout rates call <cashout-rates>`_ to learn + about any applicable fee or exchange rate. + + + **Request:** + + .. ts:def:: CashoutRequest + + interface CashoutRequest { + // Nonce to make the request idempotent. Requests with the same + // ``request_uid`` that differ in any of the other fields + // are rejected. + request_uid: ShortHashCode; + + // Optional subject to associate to the + // cashout operation. This data will appear + // as the incoming wire transfer subject in + // the user's fiat bank account. + subject?: string; + + // That is the plain amount that the user specified + // to cashout. Its $currency is the (regional) currency of the + // bank instance. + amount_debit: Amount; + + // That is the amount that will effectively be + // transferred by the bank to the user's fiat bank + // account. + // It is expressed in the fiat currency and + // is calculated after the cashout fee and the + // exchange rate. See the /cashout-rate call. + // The client needs to calculate this amount + // correctly based on the amount_debit and the cashout rate, + // otherwise the request will fail. + amount_credit: Amount; + } + + **Response:** + + :http:statuscode:`200 OK`: + The cashout request was correctly created. + This returns the `CashoutResponse` response. + :http:statuscode:`202 Accepted`: + 2FA is required for this operation. This returns the `ChallengeResponse` response. @since **v10** + :http:statuscode:`401 Unauthorized`: + Invalid or missing credentials. + :http:statuscode:`403 Forbidden`: + Missing rights. + :http:statuscode:`404 Not found`: + The account pointed by ``$USERNAME`` was not found. + :http:statuscode:`409 Conflict`: + * ``TALER_EC_BANK_TRANSFER_REQUEST_UID_REUSED``: an operation with the same ``request_uid`` but different details has been submitted before. + * ``TALER_EC_BANK_BAD_CONVERSION``: exchange rate was calculated incorrectly by the client. + * ``TALER_EC_BANK_BANK_CONVERSION_AMOUNT_TO_SMALL``: the amount of the cashout is too small. + * ``TALER_EC_BANK_UNALLOWED_DEBIT``: the account does not have sufficient funds or the amount is too low or too high. + * ``TALER_EC_BANK_CONFIRM_INCOMPLETE``: the user did not share any cashout payto to uri where to wire funds. + :http:statuscode:`501 Not Implemented`: + * ``TALER_EC_BANK_TAN_CHANNEL_NOT_SUPPORTED``: the chosen ``tan_channel`` or one of ``tan_channels`` is not currently supported. + * This server does not support conversion, client should check config response. + + **Details:** + + .. ts:def:: CashoutResponse + + interface CashoutResponse { + // ID identifying the operation being created + cashout_id: Integer; + } diff --git a/core/corebank/post-accounts-USERNAME-challenge-CHALLENGE_ID-confirm.rst b/core/corebank/post-accounts-USERNAME-challenge-CHALLENGE_ID-confirm.rst @@ -0,0 +1,29 @@ +.. http:post:: /accounts/$USERNAME/challenge/$CHALLENGE_ID/confirm + + Solves the ``CHALLENGE_ID`` challenge and allows performing the protected operation. + + When the challenge is confirmed, you can call the protected endpoint again with ``CHALLENGE_ID`` in the ``Taler-Challenge-Ids`` HTTP header and an the original request body. + + This endpoints is not authenticated. Too many unsuccessful attempts to confirm token creation challenges block the account. + + **Request:** + + .. ts:def:: ChallengeSolve + + interface ChallengeSolve { + // The TAN code that solves $CHALLENGE_ID + tan: string; + } + + **Response:** + + :http:statuscode:`204 No Content`: + The challenge is confirmed. + :http:statuscode:`404 Not Found`: + * ``TALER_EC_BANK_TRANSACTION_NOT_FOUND`` : unknown challenge TAN. + * ``TALER_EC_BANK_TAN_CHALLENGE_EXPIRED`` : expired challenge. + :http:statuscode:`409 Conflict`: + * ``TALER_EC_BANK_TAN_CHALLENGE_FAILED`` : wrong TAN. + * ``TALER_EC_BANK_TAN_CHALLENGE_EXPIRED`` : expired TAN. + :http:statuscode:`429 Too many requests`: + Too many failed confirmation attempts, a new TAN must be requested. diff --git a/core/corebank/post-accounts-USERNAME-challenge-CHALLENGE_ID.rst b/core/corebank/post-accounts-USERNAME-challenge-CHALLENGE_ID.rst @@ -0,0 +1,40 @@ +.. http:post:: /accounts/$USERNAME/challenge/$CHALLENGE_ID + + Send TAN code for the ``CHALLENGE_ID`` challenge. + + This request can be posted several times to trigger TAN retransmission when the current code has expired or too many confirmation attempts have been made. + + This endpoint is not authenticated. @since **v10** + + **Request:** + + The request body must be empty. + + **Response:** + + :http:statuscode:`200 Ok`: + The TAN code has been sent. The body will be a `ChallengeRequestResponse`. + :http:statuscode:`404 Not Found`: + * ``TALER_EC_BANK_TAN_CHANNEL_SCRIPT_FAILED``: TAN transmition failed. + * ``TALER_EC_BANK_TAN_CHALLENGE_EXPIRED``: TAN transmition failed. + The challenge was not found. + :http:statuscode:`410 Gone`: + The challenge was already solved. + :http:statuscode:`429 Too many requests`: + Too many challenges are active right now, you must wait or confirm current challenges. + :http:statuscode:`502 Bad Gateway`: + * ``TALER_EC_BANK_TAN_CHANNEL_SCRIPT_FAILED``: TAN transmition failed. + + **Details:** + + .. ts:def:: ChallengeRequestResponse + + interface ChallengeRequestResponse { + // How long does the client have to solve the + // challenge. + solve_expiration: Timestamp; + + // What is the earlist time at which the client + // may request a new challenge to be transmitted? + earliest_retransmission: Timestamp; + } diff --git a/core/corebank/post-accounts-USERNAME-token.rst b/core/corebank/post-accounts-USERNAME-token.rst @@ -0,0 +1,52 @@ +.. http:post:: /accounts/$USERNAME/token + + Create an authentification token. + + **Request:** + + .. ts:def:: TokenRequest + + interface TokenRequest { + // Scope for the token. + scope: "readonly" | "readwrite" | "revenue" | "wiregateway" | "observability"; + + // Custom token validity duration + duration?: RelativeTime; + + // Is the token refreshable into a new token during its + // validity? + // Refreshable tokens effectively provide indefinite + // access if they are refreshed in time. + refreshable?: boolean; + + // Optional token description + // @since **v4** + description?: string; + } + + **Response:** + + :http:statuscode:`200 Ok`: + Response is a `TokenSuccessResponse`. + :http:statuscode:`202 Accepted`: + 2FA is required for this operation. This returns the `ChallengeResponse` response. @since **v10** + :http:statuscode:`401 Unauthorized`: + Invalid or missing credentials. + :http:statuscode:`403 Forbidden`: + * ``TALER_EC_GENERIC_FORBIDDEN``: missing rights. + * ``TALER_EC_BANK_ACCOUNT_LOCKED``: account is locked and cannot create new token using its password. + + **Details:** + + .. ts:def:: TokenSuccessResponse + + interface TokenSuccessResponse { + // Expiration determined by the server. + // Can be based on the token_duration + // from the request, but ultimately the + // server decides the expiration. + expiration: Timestamp; + + // Opque access token. + access_token: string; + } diff --git a/core/corebank/post-accounts-USERNAME-transactions.rst b/core/corebank/post-accounts-USERNAME-transactions.rst @@ -0,0 +1,54 @@ +.. http:post:: /accounts/$USERNAME/transactions + + Create a new transaction where the bank account with the label ``USERNAME`` is **debited**. + + **Request:** + + .. ts:def:: CreateTransactionRequest + + interface CreateTransactionRequest { + // Address in the payto format of the wire transfer receiver. + // It needs at least the 'message' query string parameter. + payto_uri: string; + + // Transaction amount (in the $currency:x.y format), optional. + // However, when not given, its value must occupy the 'amount' + // query string parameter of the 'payto' field. In case it + // is given in both places, the payto_uri's takes the precedence. + amount: string; + + // Nonce to make the request idempotent. Requests with the same + // ``request_uid`` that differ in any of the other fields + // are rejected. + // @since **v4**, will become mandatory in the next version. + request_uid?: ShortHashCode; + } + + **Response:** + + :http:statuscode:`200 Ok`: + The bank responds with an `CreateTransactionResponse` object. + :http:statuscode:`202 Accepted`: + 2FA is required for this operation. This returns the `ChallengeResponse` response. @since **v10** + :http:statuscode:`400 Bad Request`: + The request was invalid or the payto://-URI used unacceptable features. + :http:statuscode:`401 Unauthorized`: + Invalid or missing credentials. + :http:statuscode:`403 Forbidden`: + Missing rights. + :http:statuscode:`404 Not found`: + The account pointed by ``$USERNAME`` was not found. + :http:statuscode:`409 Conflict`: + * ``TALER_EC_BANK_SAME_ACCOUNT`` : creditor account is the same than ``USERNAME``. + * ``TALER_EC_BANK_UNKNOWN_CREDITOR`` : creditor account was not found. + * ``TALER_EC_BANK_UNALLOWED_DEBIT`` : the account does not have sufficient funds or the amount is too low or too high. + * ``TALER_EC_BANK_TRANSFER_REQUEST_UID_REUSED``: an operation with the same ``request_uid`` but different details has been submitted before. + + **Details:** + + .. ts:def:: CreateTransactionResponse + + interface CreateTransactionResponse { + // ID identifying the transaction being created + row_id: Integer; + } diff --git a/core/corebank/post-accounts-USERNAME-withdrawals-WITHDRAWAL_ID-abort.rst b/core/corebank/post-accounts-USERNAME-withdrawals-WITHDRAWAL_ID-abort.rst @@ -0,0 +1,17 @@ +.. http:post:: /accounts/$USERNAME/withdrawals/$WITHDRAWAL_ID/abort + + Aborts ``WITHDRAWAL_ID`` operation. Has no effect on an already aborted + operation. + + **Response:** + + :http:statuscode:`204 No content`: + The withdrawal operation has been aborted. + :http:statuscode:`401 Unauthorized`: + Invalid or missing credentials. + :http:statuscode:`403 Forbidden`: + Missing rights. + :http:statuscode:`404 Not found`: + The withdrawal operation was not found. + :http:statuscode:`409 Conflict`: + The withdrawal operation has been confirmed previously and can't be aborted. diff --git a/core/corebank/post-accounts-USERNAME-withdrawals-WITHDRAWAL_ID-confirm.rst b/core/corebank/post-accounts-USERNAME-withdrawals-WITHDRAWAL_ID-confirm.rst @@ -0,0 +1,38 @@ +.. http:post:: /accounts/$USERNAME/withdrawals/$WITHDRAWAL_ID/confirm + + Confirms ``WITHDRAWAL_ID`` operation. Has no effect on an already confirmed + withdrawal operation. This call is responsible for wiring the funds to the + exchange. + + **Request:** + + .. ts:def:: BankAccountConfirmWithdrawalRequest + + interface BankAccountConfirmWithdrawalRequest { + + // Selected amount to be transferred. Optional if the + // backend already knows the amount. + // @since **v6** + amount?: Amount; + } + + + **Response:** + + :http:statuscode:`202 Accepted`: + 2FA is required for this operation. This returns the `ChallengeResponse` response. @since **v10** + :http:statuscode:`204 No content`: + The withdrawal operation has been confirmed. + :http:statuscode:`401 Unauthorized`: + Invalid or missing credentials. + :http:statuscode:`403 Forbidden`: + Missing rights. + :http:statuscode:`404 Not found`: + The operation was not found. + :http:statuscode:`409 Conflict`: + * ``TALER_EC_BANK_CONFIRM_ABORT_CONFLICT`` : the withdrawal has been aborted previously and can't be confirmed. + * ``TALER_EC_BANK_CONFIRM_INCOMPLETE`` : the withdraw operation cannot be confirmed because no exchange and reserve public key selection happened before. + * ``TALER_EC_BANK_DUPLICATE_RESERVE_PUB_SUBJECT``: the reserve public key is already used. + * ``TALER_EC_BANK_UNALLOWED_DEBIT`` : the account does not have sufficient funds or the amount is too low or too high + * ``TALER_EC_BANK_AMOUNT_DIFFERS`` : the specified amount will not work for this withdrawal (since **v6**). + * ``TALER_EC_BANK_AMOUNT_REQUIRED`` : the backend requires an amount to be specified (since **v6**). diff --git a/core/corebank/post-accounts-USERNAME-withdrawals.rst b/core/corebank/post-accounts-USERNAME-withdrawals.rst @@ -0,0 +1,54 @@ +.. http:post:: /accounts/$USERNAME/withdrawals + + Create a withdrawal operation, resulting in a ``taler://withdraw`` URI. + + **Request:** + + The request must be a `BankAccountCreateWithdrawalRequest`. + + **Response:** + + :http:statuscode:`200 Ok`: + The bank responds with an `BankAccountCreateWithdrawalResponse` object. + :http:statuscode:`401 Unauthorized`: + Invalid or missing credentials. + :http:statuscode:`403 Forbidden`: + Missing rights. + :http:statuscode:`404 Not found`: + The account pointed by ``$USERNAME`` was not found. + :http:statuscode:`409 Conflict`: + The account does not have sufficient funds. + + **Details:** + + .. ts:def:: BankAccountCreateWithdrawalRequest + + interface BankAccountCreateWithdrawalRequest { + // Amount to withdraw. If given, the wallet + // cannot change the amount. + // Optional since **v6**. + amount?: Amount; + + // Suggested amount to withdraw. The wallet can + // still change the suggestion. + // @since **v6** + suggested_amount?: Amount; + + // If true, tell the wallet not to allow the user to + // specify an amount to withdraw and to not provide + // any amount when registering with the withdrawal + // operation. The amount to withdraw will be set + // by the final ``/withdrawals/$WITHDRAWAL_ID/confirm`` step. + // @since **v8** + no_amount_to_wallet?: boolean; + } + + .. ts:def:: BankAccountCreateWithdrawalResponse + + interface BankAccountCreateWithdrawalResponse { + // ID identifying the operation being created + withdrawal_id: string; + + // URI that can be passed to the wallet to initiate the withdrawal + taler_withdraw_uri: string; + } diff --git a/core/corebank/post-accounts.rst b/core/corebank/post-accounts.rst @@ -0,0 +1,116 @@ +.. http:post:: /accounts + + Create a new bank account. Depending on the configuration, + the account creation is self-serve, or only restricted to + the administrators. + + **Request:** + + .. ts:def:: RegisterAccountRequest + + interface RegisterAccountRequest { + // Username of the account + // Must match [a-zA-Z0-9-._~]{1, 126} + username: string; + + // Password of the account used for authentication + password: string; + + // Legal name of the account owner + name: string; + + // Make this account visible to anyone? + // Defaults to false. + is_public?: boolean; + + // Make this account a taler exchange account? + // If true: + // - incoming transactions to the account that do not + // have a valid reserve public key are automatically + // - the account provides the taler-wire-gateway-api endpoints + // Defaults to false. + is_taler_exchange?: boolean; + + // Addresses where to send the TAN for protected operations. + contact_data?: ChallengeContactData; + + // Payto URI of a fiat bank account. + // Payments will be sent to this bank account + // when the user wants to convert the regional currency + // back to fiat currency outside bank. + cashout_payto_uri?: string; + + // Simple payto URI of this bank account. + // Used mostly for testing, this field is ignored if the bank payment + // method is not IBAN. + payto_uri?: string; + + // If present, set the max debit allowed for this user + // Only admin can set this property. + debit_threshold?: Amount; + + // If present, set the user conversion rate class + // Only admin can set this property. + // @since **v9** + conversion_rate_class_id?: Integer; + + // @deprecated in **v10** + // If present, enables 2FA and set the TAN channel used for challenges + // Only admin can set this property, other user can reconfig their account + // after creation. + tan_channel?: TanChannel; + + // If present, enables 2FA and set the TAN channels used for challenges + // Only admin can set this property, other user can reconfig their account + // after creation. + // @since **v10** + tan_channels?: TanChannel[]; + + // @deprecated in **v9**, use conversion_rate_class_id instead + min_cashout?: Amount; + } + + .. ts:def:: ChallengeContactData + + interface ChallengeContactData { + // E-Mail address + email?: EmailAddress; + + // Phone number. + phone?: PhoneNumber; + } + + + **Response:** + + :http:statuscode:`200 OK`: + Response is a `RegisterAccountResponse`. + :http:statuscode:`400 Bad request`: + Input data was invalid. For example, the client specified a invalid + phone number or e-mail address. + :http:statuscode:`401 Unauthorized`: + Invalid or missing credentials. + :http:statuscode:`403 Forbidden`: + Missing rights. + :http:statuscode:`409 Conflict`: + * ``TALER_EC_BANK_REGISTER_USERNAME_REUSE`` : username already used. + * ``TALER_EC_BANK_REGISTER_PAYTO_URI_REUSE`` : payto URI already used. + * ``TALER_EC_BANK_UNALLOWED_DEBIT`` : admin account does not have sufficient funds to grant bonus. + * ``TALER_EC_BANK_RESERVED_USERNAME_CONFLICT`` : a reserved username was attempted, like ``admin`` or ``bank`` + * ``TALER_EC_BANK_NON_ADMIN_PATCH_DEBT_LIMIT`` : a non-admin user has tried to create an account with a customer debt limit. + * ``TALER_EC_BANK_NON_ADMIN_SET_CONVERSION_RATE_CLASS`` : a non-admin user has tried to create an account with a conversion rate class. Since **v9** + * ``TALER_EC_BANK_NON_ADMIN_SET_TAN_CHANNEL`` : a non-admin user has tried to create an account with 2fa. + * ``TALER_EC_BANK_TAN_CHANNEL_NOT_SUPPORTED``: ``tan_channel`` or one of ``tan_channels`` is not supported, check bank config to find supported ones. + * ``TALER_EC_BANK_MISSING_TAN_INFO``: the user did not share any contact data where to send the TAN via ``tan_channel`` or one of ``tan_channels``. + * ``TALER_EC_BANK_PASSWORD_TOO_SHORT``: password is shorter than 8 characters. + * ``TALER_EC_BANK_PASSWORD_TOO_LONG``: password is longer than 64 characters. + * ``TALER_EC_BANK_CONVERSION_RATE_CLASS_UNKNOWN`` : no conversion rate class found for this id. Since **v9** + + **Details:** + + .. ts:def:: RegisterAccountResponse + + interface RegisterAccountResponse { + // Full payto URI of this bank account. + internal_payto_uri: string; + } diff --git a/core/corebank/post-conversion-rate-classes.rst b/core/corebank/post-conversion-rate-classes.rst @@ -0,0 +1,66 @@ +.. http:post:: /conversion-rate-classes + + Create a new conversion rate classe. + + Only available to the administrator. + + Since protocol **v9**. + + **Request:** + + .. ts:def:: ConversionRateClassInput + + interface ConversionRateClassInput { + // The name of this class + name: string; + + // A description of the class + description?: string; + + // Minimum fiat amount authorised for cashin before conversion + cashin_min_amount?: Amount; + + // Exchange rate to buy regional currency from fiat + cashin_ratio?: DecimalNumber; + + // Regional amount fee to subtract after applying the cashin ratio. + cashin_fee?: Amount; + + // Rounding mode used during cashin conversion + cashin_rounding_mode?: "zero" | "up" | "nearest"; + + // Minimum regional amount authorised for cashout before conversion + cashout_min_amount?: Amount; + + // Exchange rate to sell regional currency for fiat + cashout_ratio?: DecimalNumber; + + // Fiat amount fee to subtract after applying the cashout ratio. + cashout_fee?: Amount; + + // Rounding mode used during cashout conversion + cashout_rounding_mode?: "zero" | "up" | "nearest"; + } + + **Response:** + + :http:statuscode:`200 OK`: + The conversion rate class request was correctly created. + This returns the `ConversionRateClassResponse` response. + :http:statuscode:`401 Unauthorized`: + Invalid or missing credentials. + :http:statuscode:`403 Forbidden`: + Missing rights. + :http:statuscode:`409 Conflict`: + * ``TALER_EC_BANK_NAME_REUSE`` : name already used. + :http:statuscode:`501 Not implemented`: + This server does not support conversion, client should check config response. + + **Details:** + + .. ts:def:: ConversionRateClassResponse + + interface ConversionRateClassResponse { + // ID identifying the conversion rate class being created + conversion_rate_class_id: Integer; + } diff --git a/core/ebisync/get-config.rst b/core/ebisync/get-config.rst @@ -0,0 +1,29 @@ +.. http:get:: /config + + Return the protocol version and configuration information about the bank. + This specification corresponds to ``current`` protocol being version **v0**. + + **Response:** + + :http:statuscode:`200 OK`: + Response is a `Config`. + + **Details:** + + .. ts:def:: Config + + interface Config { + // Name of the API. + name: "taler-ebisync"; + + // libtool-style representation of the Bank protocol version, see + // https://www.gnu.org/software/libtool/manual/html_node/Versioning.html#Versioning + // The format is "current:revision:age". + version: string; + + // URN of the implementation (needed to interpret 'revision' in version). + implementation: string; + + // SPA display version to be used in user interfaces. + spa_version: string; + } diff --git a/core/ebisync/get-submit.rst b/core/ebisync/get-submit.rst @@ -0,0 +1,30 @@ +.. http:get:: /submit + + Obtains a list of the orders that can be used. + + **Response:** + + :http:statuscode:`200 OK`: + The server responds with a `ListSubmitOrders` object. + :http:statuscode:`401 Unauthorized`: + Invalid or missing credentials. + :http:statuscode:`403 Forbidden`: + Missing rights. + + **Details:** + + .. ts:def:: ListSubmitOrders + + interface ListSubmitOrders { + orders: SubmitOrder[]; + } + + .. ts:def:: SubmitOrder + + interface SubmitOrder { + // EBICS order id to uniquely identify this order + id: string; + + // EBICS order description provided by the EBICS server + description: string; + } diff --git a/core/ebisync/post-submit.rst b/core/ebisync/post-submit.rst @@ -0,0 +1,32 @@ +.. http:post:: /submit + + Submit an file to the EBICS server using a chosen order. + + **Request:** + + :formparam file: The file to submit. + :formparam order: The is of the EBICS order to use. + + **Response:** + + :http:statuscode:`200 OK`: + Response is a `SubmitResponse`. + :http:statuscode:`400 Bad request`: + Input data was invalid. + :http:statuscode:`401 Unauthorized`: + Invalid or missing credentials. + :http:statuscode:`403 Forbidden`: + Missing rights. + :http:statuscode:`409 Conflict`: + EBICS server validation error. + :http:statuscode:`502 Bad Gateway`: + EBICS server connection error. + + **Details:** + + .. ts:def:: SubmitResponse + + interface SubmitResponse { + // EBICS upload order ID + order: string; + } diff --git a/core/mailbox/delete-ADDRESS.rst b/core/mailbox/delete-ADDRESS.rst @@ -0,0 +1,64 @@ +.. http:delete:: /$ADDRESS + + Requests the deletion of already received messages from the + mailbox. Here, ``$ADDRESS`` must be the EdDSA public key + of the mailbox (not the hash!). + The ``ETag`` header returned by a GET request for messages + returns the ID for the first message received. + This allows the caller to select a range of messages starting + from the first message received in the last GET call + to delete. + + **Request** + + The header ``Match-If`` must be set to the ID of the first message + to delete. + The ``ETag`` value is retrieved when receiving messages via a GET + request. + For example, a ``Match-If`` header value of 2 and a count field of + 5 will delete messages from ID 2 to N such that up to 5 messages are + deleted. + The ``Taler-Mailbox-Delete-Signature`` header must be set with a + Base32-Crockfor encoded signature over four 32 bit values in + network byte order: ``NBO(16)||NBO(TALER_SIGNATURE_MAILBOX_DELETE_MESSAGES)||NBO(Etag)||NBO(count)`` + where ``TALER_SIGNATURE_MAILBOX_DELETE_MESSAGES`` is a signature purpose value registered in + GANA. + + :query count=NUMBER: *Optional.* If specified, + the Mailbox service will delete up to ``NUMBER`` + of new messages starting from the ID provided + in ``Match-If``. + If the parameter is not provided, only a single + message will be deleted. + + + **Details:** + + .. _MessageDeletionRequest: + .. ts:def:: MessageDeletionRequest + + interface MessageDeletionRequest { + + // Number of messages to delete. (Starting from the beginning + // of the latest GET response). + count: Integer; + + // Signature by the mailbox's private key affirming + // the deletion of the messages, of purpuse + // ``TALER_SIGNATURE_MAILBOX_DELETE_MESSAGES``. + signature: string; + + } + + **Response** + + :http:statuscode:`204 No Content`: + Deletion complete. + :http:statuscode:`403 Forbidden`: + The ``signature`` is invalid. + This response comes with a standard `ErrorDetail` response. + :http:statuscode:`404 Not found`: + The checksum does not match the messages currently at the + head of the mailbox, or ``count`` is larger + than the number of messages currently in the mailbox. + This response comes with a standard `ErrorDetail` response. diff --git a/core/mailbox/get-H_MAILBOX.rst b/core/mailbox/get-H_MAILBOX.rst @@ -0,0 +1,35 @@ +.. http:get:: /$H_MAILBOX + + Endpoint that returns unread messages in ``$H_MAILBOX``. + The number of messages returned by the service can be limited. + If the request is simply repeated, the same messages will be + returned again (or possibly more if additional messages arrived + and the total number is below the service's current internal limit). + To receive additional messages, the client generally has to first + explicitly delete already downloaded messages from the mailbox. + If messages are returned, the ``ETag`` header will be set + containing the ID of the first message + for use in any potential delete requests that require the message ID. + + **Request:** + + :query timeout_ms=NUMBER: *Optional.* If specified, + the Mailbox service will wait up to ``NUMBER`` + milliseconds for the arrival of new messages + before sending the HTTP response. Note that if the + mailbox is non-empty, the service will always return + immediately with the messages in the mailbox, and not + wait for additional messages to arrive. + + **Response** + + :http:statuscode:`200 Ok`: + Messages are returned in binary format, 256 bytes per message, + starting with the ephemeral key and followed by + the encrypted body. Messages are not encapsulated in JSON! + :http:statuscode:`204 No Content`: + The mailbox is empty. + :http:statuscode:`429 Too Many Requests`: + The system is currently experiencing a too high request + load and is unable to accept the message for delivery. + The response format is given by `MailboxRateLimitedResponse`_. diff --git a/core/mailbox/get-config.rst b/core/mailbox/get-config.rst @@ -0,0 +1,59 @@ +.. http:get:: /config + + Return the protocol version and currency supported by this service. + + **Response:** + + :http:statuscode:`200 OK`: + The body is a `VersionResponse`. + + **Details:** + + .. ts:def:: VersionResponse + + interface VersionResponse { + // libtool-style representation of the Merchant protocol version, see + // https://www.gnu.org/software/libtool/manual/html_node/Versioning.html#Versioning + // The format is "current:revision:age". + version: string; + + // Name of the protocol. + name: "taler-mailbox"; + + // Fee per message. + message_fee: Amount; + + // Fixed size of message body. + message_body_bytes: Integer; + + // Maximum number of messages in a + // single response. + message_response_limit: Integer; + + // How long will the service store a message + // before giving up on delivery? + delivery_period: RelativeTime; + + // How much is the cost of a single + // registration (update) of a mailbox + // May be 0 for a free update/registration. + registration_update_fee: Amount + + // How much is the cost of a single + // registration period (30 days) of a mailbox + // May be 0 for a free registration. + monthly_fee: Amount + + // How much is the cost to send a single + // message to a mailbox. + // May be 0 for free message sending. + message_fee: Amount + + // How many messages can be send and + // are stored by the service for free. + // After the quota is reached, the + // regular message_fee applies. + // May be 0 for no free quota. + free_message_quota: Integer + + } diff --git a/core/mailbox/get-info-H_MAILBOX.rst b/core/mailbox/get-info-H_MAILBOX.rst @@ -0,0 +1,58 @@ +.. http:get:: /info/$H_MAILBOX + + Endpoint that returns mailbox metadata including signing and encryption keys for ``$H_MAILBOX``. + + **Response** + + :http:statuscode:`200 Ok`: + Info is returned in a `MailboxMetadata` response, + :http:statuscode:`404 Not Found`: + This mailbox is not registered. + :http:statuscode:`429 Too Many Requests`: + The system is currently experiencing a too high request + load and is unable to accept the message for delivery. + The response format is given by `MailboxRateLimitedResponse`_. + + + **Details:** + + .. _MailboxMetadata: + .. ts:def:: MailboxMetadata + + interface MailboxMetadata { + + // The mailbox signing key. + // Note that ``$H_MAILBOX == H(signing_key)``. + // Note also how this key cannot be updated + // as it identifies the mailbox. + // Base32 crockford-encoded. + signing_key: string; + + // Type of key. + // Currently only + // EdDSA keys are supported. + signing_key_type: "EdDSA"; + + // The mailbox encryption key. + // This is a HPKE public key + // Currently, only the X25519 format + // for use in a X25519-DHKEM (RFC 9180) + // is supported. + // Base32 crockford-encoded. + encryption_key: string; + + // Type of key. + // Currently only + // X25519 keys are supported. + encryption_key_type: "X25519"; + + // Expiration of this mailbox. + // Unix epoch (seconds) + expiration: Timestamp; + + // Optional info string that can be + // chosen by the mailbox owner. + // This may contain a Keyoxide proof for the mailbox + // in order to link it to the owners profile + info?: string; + } diff --git a/core/mailbox/post-H_MAILBOX.rst b/core/mailbox/post-H_MAILBOX.rst @@ -0,0 +1,46 @@ +.. http:post:: /$H_MAILBOX + + Puts a message into ``$H_MAILBOX``. + ``$H_MAILBOX`` is the SHA512 of an EdDSA public key. + + **Request** + + The content of the request must be the message with a size of + exactly message_body_bytes (see `VersionResponse`). + + **Response** + + :http:statuscode:`204 No Content` + Message was stored and will be delivered. + :http:statuscode:`403 Forbidden` + The specified order ID in the ``Mailbox-Order-Id`` header does not + permit sending of this message. Possible reasons include the order + being for a different message, unpaid or + malformed. + This response comes with a standard `ErrorDetail` response. + :http:statuscode:`429 Too Many Requests`: + The system is currently experiencing a too high request + load and is unable to accept the message for delivery. + The response format is given by `MailboxRateLimitedResponse`_. + :http:statuscode:`402 Payment Required` + Client needs to make a Taler payment before proceeding. See + standard Taler payment procedure. + + + **Details:** + + .. _MailboxRateLimitedResponse: + .. ts:def:: MailboxRateLimitedResponse + + interface MailboxRateLimitedResponse { + + // Taler error code, TALER_EC_MAILBOX_DELIVERY_RATE_LIMITED. + code: Integer; + + // When the client should retry. + retry_delay: RelativeTime; + + // The human readable error message. + hint: string; + + } diff --git a/core/mailbox/post-register.rst b/core/mailbox/post-register.rst @@ -0,0 +1,44 @@ +.. http:post:: /register + + Requests the registration or update of a mailbox. + May be used to update encryption keys. + May incur cost. + The mailbox identity is given through the keys field + in the ``MailboxMetadata`` field. + + **Request** + + The body of the request must be a ``MailboxRegistrationRequest``. + + **Details:** + + .. _MailboxRegistrationRequest: + .. ts:def:: MailboxRegistrationRequest + + interface MailboxRegistrationRequest { + + // Keys to add/update for the mailbox. + mailbox_metadata: MailboxMetadata; + + // Signature by the mailbox's signing key affirming + // the update of keys, of purpose + // ``TALER_SIGNATURE_MAILBOX_REGISTER``. + // The signature is created over the SHA-512 hash + // of (encryptionKeyType||encryptionKey||expiration) + // Base32 crockford-encoded. + // The signature system is defined through the + // signing_key_type in the keys field. + signature: string; + + } + + **Response** + + :http:statuscode:`204 No Content`: + Update/creation complete. + :http:statuscode:`403 Forbidden`: + The ``signature`` is invalid. + This response comes with a standard `ErrorDetail` response. + :http:statuscode:`402 Payment Required` + Client needs to make a Taler payment before proceeding. See + standard Taler payment procedure. diff --git a/core/taldir/get-H_ALIAS.rst b/core/taldir/get-H_ALIAS.rst @@ -0,0 +1,27 @@ +.. http:get:: /$H_ALIAS + + Lookup the target URI associated with + an alias in the TalDir. Here, + ``$H_ALIAS`` is the SHA-512 hash of a prefix-free encoding of the + alias to be registered in Crockford base32 encoding. + + **Response** + + Standard HTTP cache control headers are used to specify how long the + registration is still expected to be valid. + + :http:statuscode:`200 Ok`: + Registration information returned, of type `MailboxDetailResponse` + :http:statuscode:`404 Not found`: + The alias is unknown (original registration may have expired). + + .. _MailboxDetailResponse: + .. ts:def:: MailboxDetailResponse + + interface MailboxDetailResponse { + + // Target URI to associate with this alias. + target_uri: string; + + + } diff --git a/core/taldir/get-config.rst b/core/taldir/get-config.rst @@ -0,0 +1,38 @@ +.. http:get:: /config + + Return the protocol version and currency supported by this service. + + **Response:** + + :http:statuscode:`200 OK`: + The body is a `VersionResponse`. + + .. ts:def:: VersionResponse + + interface VersionResponse { + // libtool-style representation of the Merchant protocol version, see + // https://www.gnu.org/software/libtool/manual/html_node/Versioning.html#Versioning + // The format is "current:revision:age". + version: string; + + // Name of the protocol. + name: "taler-directory"; + + // Supported alias types + alias_types: TaldirAliasType[]; + + // fee for one month of registration + monthly_fee: Amount; + + } + + .. ts:def:: TaldirAliasType + + interface TaldirAliasType { + // Name of the alias type, e.g. "email" or "sms". + name: string; + + // per challenge fee + challenge_fee: Amount; + + } diff --git a/core/taldir/get-register-H_ALIAS-PINTAN.rst b/core/taldir/get-register-H_ALIAS-PINTAN.rst @@ -0,0 +1,27 @@ +.. http:get:: /register/$H_ALIAS/$PINTAN?alias=$ALIAS + + Endpoint that generates an HTML Web site with a link for completing the + registration. Useful to open the registration challenge in a browser (say if + it was received on a different device than where the wallet is running). + Does NOT complete the registration, as some providers automatically click on + all links in messages. Yes, we do not like them doing so either, but ``GET`` + is a "safe" method according to the HTTP standard, so technically this is + allowed. + + Opening the link will allow the user to do the POST call to this endpoint. + If the Taler wallet can somehow intercept the URL (say for SMS, if it has the right + permissions) it can skip this request and directly do the POST, as all of + the required new information is already encoded in the URL. + + Note that the wallet must be involved before the POST is made, as the + ``target_uri`` from the registration must be hashed with the ``$PINTAN`` + to protect the user against phishing. Otherwise, someone else might attempt + a concurrent registration of a different public key, and the user might + accidentally authorize the registration of the public key of a different + wallet. + ``$H_ALIAS`` is the SHA-512 hash of a prefix-free encoding of the + alias to be registered in Crockford Base32 encoding, specifically: + ``SHA-512(len($ALIASTYPE)+len($ALIAS)||$ALIASTYPE||$ALIAS)`` + The service verifies that ``$ALIAS`` is, in fact, the preimage of ``$H_ALIAS`` + and ``$ALIAS`` as well as the ``inbox_uri`` are displayed to the user + for verification. diff --git a/core/taldir/post-H_ALIAS.rst b/core/taldir/post-H_ALIAS.rst @@ -0,0 +1,32 @@ +.. http:post:: /$H_ALIAS + + This request is the last step of a registration, proving to the TalDir that + the user of the wallet is indeed able to receive messages for the specified + alias. + ``$H_ALIAS`` is the SHA-512 hash of a prefix-free encoding of the + alias to be registered in Crockford Base32 encoding. + + **Request** + + .. ts:def:: IdentityConfirmation + + interface IdentityConfirmation { + // The solution is the SHA-512 hash of the challenge ($PINTAN) value + // chosen by TalDir concatenated with the ``inbox_uri`` (both strings + // are hashed excluding the 0-terminator). + // The hash is provided as string in Crockford base32 encoding. + solution: HashCode; + + } + + **Response** + + :http:statuscode:`204 No Content`: + Registration complete. + :http:statuscode:`403 Forbidden`: + The ``solution`` is invalid. Retrying immediately is allowed. + :http:statuscode:`404 Not found`: + The alias is unknown (original registration attempt may have expired). + :http:statuscode:`429 Too Many Requests`: + The client exceeded the number of allowed attempts for solving + a challenge for this alias in the given timeframe. diff --git a/core/taldir/post-register-ALIASTYPE.rst b/core/taldir/post-register-ALIASTYPE.rst @@ -0,0 +1,79 @@ +.. http:post:: /register/$ALIASTYPE + + Endpoint to register, extend or modify the registration for an alias in + the directory. + Here, $ALIASTYPE is the type of alias to register, e.g. "email", or "phone". + Supported alias types are listed in the VersionResponse. + Note that duration should be given as a multiple of a month in microseconds. + If the duration is not a multiple of a month it will be rounded to the + nearest multiple. Halfway values will be rounded away from zero. + The cost calculation and resulting registration validity will be adjusted + automatically. + In order to only modify the data, the duration may be set to 0. + When the call is made with unmodified data and a duration of 0, the + endpoint will return how long this registration is currently paid for. + In order to delete the mapping, the target URI may be set to the empty string. + When the call is made with the empty string, and upon re-validation, the mapping + will be deleted. + + **Request** + + .. ts:def:: IdentityMessage + + interface IdentityMessage { + // Alias, in $ALIASTYPE-specific format + alias: string; + + // Target URI to associate with this alias. + target_uri: string; + + // For how long should the registration last/be extended. + duration: RelativeTime; + + } + + **Response** + + :http:statuscode:`200 Ok` + Registration already exists for this alias for the specified duration. + Returns for how long this registration is paid for. + The response format is given by `AlreadyPaidResponse`_. + :http:statuscode:`202 Accepted` + Registration was initiated, the client should check for receiving + a challenge at the alias where registration was attempted. + :http:statuscode:`402 Payment Required` + Client needs to make a Taler payment before proceeding. See + standard Taler payment procedure. + :http:statuscode:`404 Not found` + The TalDir service does not support the specified alias type. + This response comes with a standard `ErrorDetail` response. + :http:statuscode:`429 Too Many Requests`: + The client exceeded the number of allowed attempts for initiating + a challenge for this alias in the given timeframe. + The response format is given by `RateLimitedResponse`_. + + .. _RateLimitedResponse: + .. ts:def:: RateLimitedResponse + + interface RateLimitedResponse { + + // Taler error code, TALER_EC_TALDIR_REGISTER_RATE_LIMITED. + code: Integer; + + // At what frequency are new registrations allowed. + request_frequency: RelativeTime; + + // The human readable error message. + hint: string; + + } + + .. _AlreadyPaidResponse: + .. ts:def:: AlreadyPaidResponse + + interface AlreadyPaidResponse { + + // The remaining duration for which this registration is still paid for + valid_for: RelativeTime; + + }