taler-docs

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

commit 204aae80892686255339e34b0fea8fc7af921df5
parent 7db3ac86eb1a71421a5caee29668bbfa4a324c08
Author: Florian Dold <florian@dold.me>
Date:   Thu, 21 Sep 2023 15:36:23 +0200

rename API implemented by fakebank/libeufin-bank to corebank API

Diffstat:
Acore/api-corebank.rst | 929+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Dcore/api-libeufin-bank.rst | 929-------------------------------------------------------------------------------
Mcore/index-bank-apis.rst | 2+-
3 files changed, 930 insertions(+), 930 deletions(-)

diff --git a/core/api-corebank.rst b/core/api-corebank.rst @@ -0,0 +1,929 @@ +.. + This file is part of GNU TALER. + + Copyright (C) 2014-2020 Taler Systems SA + + TALER is free software; you can redistribute it and/or modify it under the + terms of the GNU Affero General Public License as published by the Free Software + Foundation; either version 2.1, or (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License along with + TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> + +.. target audience: developer, core developer + +.. _libeufin-bank-api: + +==================== +Taler Core Bank API +==================== + +.. contents:: Table of Contents + +Introduction +------------ + +The Libeufin bank provides a minimal core banking system. In addition to that, +it provides features for local/regional currencies. + +Authentication +-------------- + +Some requests require the client to authenticate via HTTP Basic auth (RFC 7617) +or using a bearer token which can be obtained or refreshed from the +``/accounts/$USERNAME/token`` endpoint. +When using Basic authentication, the user-id must be the libeufin-bank +username, and the password the password for the corresponding user. + +Another way to obtain a login token is by manually configuring it for certain +endpoints. For example, the exchange could give an auditor read-only access to +the taler-wire-gateway facade via such a manually configured access token. + +The ``admin`` user is a special, hard-coded username. Some requests require the +client to authenticate as the admin. + +.. http:post:: /accounts/$USERNAME/token + + See :ref:`DD 48 token endpoint <dd48-token>`. + + +Libeufin Bank Web UI +-------------------- + +The web UI for the libeufin-bank is typically served under ``/``. + +Config +------ + +.. http:get:: /config + + **Response:** + + .. ts:def:: Config + + interface Config { + // Name of this API, always "libeufin-bank". + name: string; + + // API version in the form $n:$n:$n + version: string; + + // If 'true', the server provides local currency + // conversion support. + // If missing or false, some parts of the API + // are not supported and return 404. + have_cashout?: boolean; + + // Fiat currency. That is the currency in which + // cash-out operations ultimately wire money. + // Only applicable if have_cashout=true. + fiat_currency?: string; + } + + +Account Management +------------------ + +.. _libeufin-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 + username: string; + + // Password. + password: string; + + // Legal name of the account owner + name: string; + + // Defaults to false. + is_public?: boolean; + + // Is this 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 transactions. + // Currently only used for cashouts. + // If missing, cashouts will fail. + // In the future, might be used for other transactions + // as well. + challenge_contact_data?: ChallengeContactData; + + // 'payto' address pointing a bank account + // external to the libeufin-bank. + // Payments will be sent to this bank account + // when the user wants to convert the local currency + // back to fiat currency outside libeufin-bank. + cashout_payto_uri?: string; + + // Internal payto URI of this bank account. + // Used mostly for testing. + internal_payto_uri?: string; + } + + .. ts:def:: ChallengeContactData + + interface ChallengeContactData { + + // E-Mail address + email?: EmailAddress; + + // Phone number. + phone?: PhoneNumber; + } + + + **Response:** + + :http:statuscode:`204 No content`: + The account was successfully created. + :http:statuscode:`400 Bad request`: + Input data was invalid. For example, the client specified a invalid + phone number or e-mail address. + :http:statuscode:`403 Forbidden`: + The response should indicate one of the following reasons. + + * A reserved username was attempted, like ``admin`` or ``bank``. + * An unauthorized user tried to create the account + + :http:statuscode:`409 Conflict`: + The internal account payto URI or username already exists. + +.. _delete-account: + +.. http:delete:: /accounts/$USERNAME + + Delete the account whose username is ``$USERNAME``. The deletion + succeeds only if the balance is *zero*. + + **Response:** + + :http:statuscode:`204 No content`: + The account was successfully deleted. + :http:statuscode:`403 Forbidden`: + The request specified a reserved internal username, like + ``admin`` or ``bank``. + :http:statuscode:`404 Not found`: + The username was not found. + :http:statuscode:`412 Precondition failed`: + The balance was not zero. + + +.. _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 transactions. + // Currently only used for cashouts. + // If missing, cashouts will fail. + // In the future, might be used for other transactions + // as well. + challenge_contact_data?: ChallengeContactData; + + // 'payto' address pointing a bank account + // external to the libeufin-bank. + // Payments will be sent to this bank account + // when the user wants to convert the local currency + // back to fiat currency outside libeufin-bank. + cashout_address?: string; + + // Legal name associated with $username. + // When missing, the old name is kept. + name?: string; + + // If present, change the is_exchange configuration. + // See `RegisterAccountRequest` + is_exchange?: boolean; + } + + **Response:** + + :http:statuscode:`204 No content`: + Operation successful. + + :http:statuscode:`403 Forbidden`: + The rights to change ``$USERNAME`` are not sufficient. + That includes the case where a correctly authenticated + user tries to change their legal name. It also + includes the case where 'admin' tries to change its + own account. + + :http:statuscode:`404 Not found`: + The account pointed by ``$USERNAME`` + was not found. + + +.. _account-password-reconfig: + +.. http:patch:: /accounts/$USERNAME/auth + + Allows changing the account's password. + + **Request:** + + .. ts:def:: AccountPasswordChange + + interface AccountPasswordChange { + + // New password. + new_password: string; + } + + **Response:** + + :http:statuscode:`204 No content`: + Operation successful. + + +.. _account-list: + +.. http:get:: ${BANK_API_BASE_URL}/public-accounts + + Show those accounts whose histories are publicly visible. For example, + accounts from donation receivers. As such, this request is unauthenticated. + + **Response** + + **Details** + + .. ts:def:: PublicAccountsResponse + + interface PublicAccountsResponse { + public_accounts: PublicAccount[]; + } + + .. ts:def:: PublicAccount + + interface PublicAccount { + payto_uri: string; + + balance: Balance; + + // The account name (=username) of the + // libeufin-bank account. + account_name: string; + } + + +.. 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 filter_name: *Optional.* + Pattern to filter on the account 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. + + **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:`403 Forbidden`: + A ordinary user invoked this call. + + **Details:** + + .. ts:def:: ListBankAccountsResponse + + interfaces ListBankAccountsResponse { + accounts: AccountMinimalData[]; + } + + .. ts:def:: Balance + + interface Balance { + amount: Amount; + credit_debit_indicator: "credit" | "debit"; + } + + .. ts:def:: AccountMinimalData + + interface AccountMinimalData { + // Username + username: string; + + // Legal name of the account owner. + name: string; + + // current balance of the account + balance: Balance; + + // Number indicating the max debit allowed for the requesting user. + debit_threshold: Amount; + } + +.. _libeufin-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 libeufin-bank responds with an `AccountData` object. + + **Details:** + + .. ts:def:: AccountData + + interface AccountData { + // Legal name of the account owner. + name: string; + + // Available balance on the account. + balance: Balance; + + // payto://-URI of the account. + payto_uri: string; + + // Number indicating the max debit allowed for the requesting user. + debit_threshold: Amount; + + contact_data?: ChallengeContactData; + + // 'payto' address pointing the bank account + // where to send cashouts. 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; + } + +Transactions +------------ + +.. http:get:: ${BANK_API_BASE_URL}/accounts/${account_name}/transactions + + Retrieve a subset of transactions related to $account_name. Without + query parameters, it returns the last 5 transactions. + + The list of returned transactions is determined by a row ID *starting point* + and a signed non-zero integer *delta*: + + * If *delta* is positive, return a list of up to *delta* transactions (all matching + the filter criteria) strictly **after** the starting point. The transactions are sorted + in **ascending** order of the row ID. + * If *delta* is negative, return a list of up to *-delta* transactions (all matching + the filter criteria) strictly **before** the starting point. The transactions are sorted + in **descending** order of the row ID. + + If *starting point* is not explicitly given, it defaults to: + + * A value that is **smaller** than all other row IDs if *delta* is **positive**. + * A value that is **larger** than all other row IDs if *delta* is **negative**. + + **Request** + + :query long_poll_ms: Optional number to express how many milliseconds the server + should wait for at least one result to be shown. If not given, the server + responds immediately, regardless of the result. + :query start: *Optional.* + Row identifier to explicitly set the *starting point* of the query. + :query delta: + The *delta* value that determines the range of the query. + + **Response** + + .. ts:def:: BankAccountTransactionsResponse + + interface BankAccountTransactionsResponse { + transactions: BankAccountTransactionInfo[]; + } + +.. http:get:: ${BANK_API_BASE_URL}/accounts/${account_name}/transactions/${transaction_id} + + **Response** + + Retrieve the transaction whose identifier is ``transaction_id``, + in the following format: + + .. ts:def:: BankAccountTransactionInfo + + interface BankAccountTransactionInfo { + creditor_payto_uri: string; + debtor_payto_uri: string; + + amount: Amount; + direction: "debit" | "credit"; + + subject: string; + + // Transaction unique ID. Matches + // $transaction_id from the URI. + row_id: number; + date: Timestamp; + } + + +.. http:post:: ${BANK_API_BASE_URL}/accounts/${account_name}/transactions + + Create a new transaction where the bank account with the label ``account_name`` is **debited**. + + **Request** + + .. ts:def:: BankAccountTransactionCreate + + interface CreateBankAccountTransactionCreate { + + // 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; + } + + **Response** + + :http:statuscode:`200 OK`: + the transaction has been created. + + :http:statuscode:`400 Bad Request`: + the request was invalid or the payto://-URI used unacceptable features. + + +Taler Withdrawals +----------------- + +.. http:post:: ${BANK_API_BASE_URL}/accounts/${account_name}/withdrawals + + Create a withdrawal operation, resulting in a ``taler://withdraw`` URI. + + **Request** + + .. ts:def:: BankAccountCreateWithdrawalRequest + + interface BankAccountCreateWithdrawalRequest { + // Amount to withdraw. + amount: Amount; + } + + **Response** + + .. ts:def:: BankAccountCreateWithdrawalResponse + + interface BankAccountCreateWithdrawalResponse { + // ID of the withdrawal, can be used to view/modify the withdrawal operation. + withdrawal_id: string; + + // URI that can be passed to the wallet to initiate the withdrawal. + taler_withdraw_uri: string; + } + + :http:statuscode:`403 Forbidden`: + The operation was rejected due to insufficient funds. + +.. http:get:: ${BANK_API_BASE_URL}/accounts/${account_name}/withdrawals/${withdrawal_id} + + Query the status of a withdrawal operation. + + **Response** + + **Details** + + .. ts:def:: BankAccountGetWithdrawalResponse + + interface BankAccountGetWithdrawalResponse { + // Amount that will be withdrawn with this withdrawal operation. + amount: Amount; + + // Was the withdrawal aborted? + aborted: boolean; + + // Has the withdrawal been confirmed by the bank? + // The wire transfer for a withdrawal is only executed once + // both ``confirmation_done`` is ``true`` and ``selection_done`` is ``true``. + confirmation_done: boolean; + + // Did the wallet select reserve details? + selection_done: boolean; + + // Reserve public key selected by the exchange, + // only non-null if ``selection_done`` is ``true``. + selected_reserve_pub: string | null; + + // Exchange account selected by the wallet, or by the bank + // (with the default exchange) in case the wallet did not provide one + // through the Integration API. + selected_exchange_account: string | null; + } + + +.. http:post:: ${BANK_API_BASE_URL}/accounts/${account_name}/withdrawals/${withdrawal_id}/abort + + Abort a withdrawal operation. Has no effect on an already aborted withdrawal operation. + + :http:statuscode:`200 OK`: The withdrawal operation has been aborted. The response is an empty JSON object. + :http:statuscode:`409 Conflict`: The reserve operation has been confirmed previously and can't be aborted. + + +.. http:post:: ${BANK_API_BASE_URL}/accounts/${account_name}/withdrawals/${withdrawal_id}/confirm + + Confirm a withdrawal operation. Has no effect on an already confirmed withdrawal operation. + This call is responsible of wiring the funds to the exchange. + + **Response** + + :http:statuscode:`200 OK`: + The withdrawal operation has been confirmed. The response is an empty JSON object. + :http:statuscode:`409 Conflict`: + The withdrawal has been aborted previously and can't be confirmed. + :http:statuscode:`422 Unprocessable Entity` (New): + The withdraw operation cannot be confirmed because no exchange and reserve public key selection happened before. + +Cashouts +-------- + +.. _account-cashout: + +.. http:post:: /accounts/$USERNAME/cashouts + + Initiates a conversion to fiat currency. The external + bank account to be + credited is the one specified at registration time via the + *cashout_address* parameter. The libeufin-bank internal account + is specified via ``$USERNAME``. + The bank sends a TAN to the customer to let them confirm the + operation. The request is only available to ordinary users, not + to the administrator. + + .. note:: + + Consult the `cashout rates call <cashout-rates_>`_ to learn + about any applicable fee or exchange rate. + + .. note:: + + FIXME: Eventually, the env variables will be replaced with + configuration settings. + + To test this operation without relying on any SMS/E-mail provider, + Libeufin offers two methods: defining an environment variable called + ``LIBEUFIN_CASHOUT_TEST_TAN`` or specifying the value ``file`` to + the ``tan_channel`` field of the `request object <cashout-request_>`_. + Assuming ``LIBEUFIN_CASHOUT_TEST_TAN`` is set to *T*, every */confirm* + operation can use *T* as the TAN. Setting instead the ``tan_channel`` + field to ``file`` will cause the server to (over)write every TAN to + ``/tmp/libeufin-cashout-tan.txt``. If both are used, the environment + variable takes the precedence. + + + **Request:** + + `CashoutRequest <cashout-request_>`_ + + .. ts:def:: TanChannel + + enum TanChannel { + SMS = "sms", + EMAIL = "email", + FILE = "file" + } + + .. _cashout-request: + + .. ts:def:: CashoutRequest + + interface CashoutRequest { + + // Optional subject to associate to the + // cashout operation. This data will appear + // as the incoming wire transfer subject in + // the user's external bank account. + subject?: string; + + // That is the plain amount that the user specified + // to cashout. Its $currency is the (regional) currency of the + // libeufin-bank instance. + amount_debit: Amount; + + // That is the amount that will effectively be + // transferred by the bank to the user's bank + // account, that is external to the regional currency. + // It is expressed in the fiat currency and + // is calculated after the cashout fee and the + // exchange rate. See the /cashout-rates 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; + + // Which channel the TAN should be sent to. If + // this field is missing, it defaults to SMS. + // The default choice prefers to change the communication + // channel respect to the one used to issue this request. + tan_channel?: TanChannel; + } + + **Response:** + + :http:statuscode:`202 Accepted`: + The cashout request was correctly created and + the TAN authentication now is pending. + This returns the `CashoutPending` response. + :http:statuscode:`409 Conflict`: + The user did not share any contact data where to send the TAN, + the account does not have sufficient funds, or the + exchange rate was calculated incorrectly by the client. + :http:statuscode:`503 Service unavailable`: + The bank does not support the TAN channel for this operation. + + **Details:** + + .. ts:def:: CashoutPending + + interface CashoutPending { + // ID identifying the operation being created + // and now waiting for the TAN confirmation. + cashout_id: string; + } + + +.. _cashout-abort: + +.. http:post:: /accounts/$USERNAME/cashouts/$CASHOUT_ID/abort + + Aborts the ``$CASHOUT_ID`` operation. + + **Response:** + + :http:statuscode:`204 No content`: + ``$CASHOUT_ID`` was found in the *pending* state + and got successfully aborted. + :http:statuscode:`404 Not found`: + ``$CASHOUT_ID`` is not found. Note: that happens + also when ``$CASHOUT_ID`` got aborted before this request. + :http:statuscode:`409 Conflict`: + ``$CASHOUT_ID`` was already confirmed. + + +.. _cashout-confirm: + +.. http:post:: /accounts/$USERNAME/cashouts/$CASHOUT_ID/confirm + + Confirms the ``$CASHOUT_ID`` operation by providing its + TAN. The request should still be authenticated with + the users credentials. + + **Request:** + + .. ts:def:: CashoutConfirm + + interface CashoutConfirm { + // the TAN that confirms $CASHOUT_ID. + tan: string; + } + + **Response:** + + :http:statuscode:`204 No content`: + The request succeeded, either for the first time, or it already was + confirmed previously (idempotency!). + :http:statuscode:`403 Forbidden`: + Wrong TAN or bad credentials. + :http:statuscode:`404 Not found`: + ``$CASHOUT_ID`` is not found. Note: that happens + also when ``$CASHOUT_ID`` got aborted before this request. + :http:statuscode:`409 Conflict`: + The user changed their cash-out address between the creation and the confirmation of ``$CASHOUT_ID``. + + +.. _cashout-rates: + +.. http:get:: /cashout-rate + + This public endpoint allows clients to calculate + the exchange rate between the regional currency + and the external 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-out operations. + At least one of the two query parameters must be provided. If both are + given, then the server checks their correctness. Amounts must include the + currency. + + **Request:** + + :query amount_debit: this is the amount that the user will get + deducted from their regional bank account. + + :query amount_credit: this is the amount that the user will receive + in their fiat bank account. + + **Response:** + + .. 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:statuscode:`200 Ok`: + Response is a `CashoutConversionResponse`. + :http:statuscode:`400 Bad request`: + Both parameters have been provided and the calculation is not correct, + or none of them has been provided. + :http:statuscode:`404 Not found`: + The server does not support local currency conversion. + + +.. _circuit-cashouts: + +.. http:get:: /accounts/$USERNAME/cashouts + + Returns the list of all the (pending and confirmed) cash-out operations + for an account. + + **Response:** + + .. ts:def:: Cashouts + + interface Cashouts { + // Every string represents a cash-out operation ID. + cashouts: CashoutInfo[]; + } + + .. ts:def:: CashoutInfo + + interface CashoutInfo { + cashout_id: string; + status: "pending" | "confirmed"; + } + + :http:statuscode:`200 OK`: + At least one cash-out operation was found. + + :http:statuscode:`204 No Content`: + No cash-out operations were found at the bank + +.. http:get:: /cashouts + + Returns the list of all the (pending and confirmed) cash-out operations + for **all** accounts. + + Typically can only be used by the administrators. + + .. note:: + + We might want to add a filter in the future to only + query pending cashout operations. + + **Response:** + + .. ts:def:: GlobalCashouts + + interface GlobalCashouts { + // Every string represents a cash-out operation ID. + cashouts: { cashout_id: string, username: string}[]; + } + + .. ts:def:: GlobalCashoutInfo + + interface GlobalCashoutInfo { + cashout_id: string; + username: string; + status: "pending" | "confirmed"; + } + + :http:statuscode:`200 OK`: + At least one cash-out operation was found. + + :http:statuscode:`204 No Content`: + No cash-out operations were found at the bank + +.. _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:** + + `CashoutStatusResponse <cashout-status_>`_ + + .. _cashout-status: + + .. ts:def:: CashoutStatus + + interface CashoutStatusResponse { + status: "pending" | "confirmed"; + + // Amount debited to the internal + // regional currency bank account. + amount_debit: Amount; + + // Amount credited to the external bank account. + amount_credit: Amount; + + // Transaction subject. + subject: string; + + // Fiat bank account that will receive the cashed out amount. + // Specified as a payto URI. + credit_payto_uri: string; + + // Time when the cashout was created. + creation_time: Timestamp; + + // Time when the cashout was confirmed via its TAN. + // Missing when the operation wasn't confirmed yet. + confirmation_time?: Timestamp; + } + + **Response:** + + :http:statuscode:`404 Not found`: + The cashout operation was not found. + Aborted cashout operations will also not be found. + +Taler Bank Integration API +-------------------------- + +.. 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. + +Taler Wire Gateway API +---------------------- + +.. 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_exchange=true``. + +Taler Revenue API +---------------------- + +.. http:any:: /accounts/$USERNAME/taler-revenue/* + + All endpoints under this prefix are specified + by the :doc:`GNU Taler Revenue API </core/api-bank-revenue>`. + +EBICS Host +---------- + +The Taler bank can be configured to serve bank account transactions and allow +payment initiations via the EBICS protocol. + +This is an optional feature, not all implementations of the API support it. + +.. http:post:: /ebicshost + + EBICS base URL. This URL allows clients to make EBICS requests to one of + the configured EBICS hosts. + diff --git a/core/api-libeufin-bank.rst b/core/api-libeufin-bank.rst @@ -1,929 +0,0 @@ -.. - This file is part of GNU TALER. - - Copyright (C) 2014-2020 Taler Systems SA - - TALER is free software; you can redistribute it and/or modify it under the - terms of the GNU Affero General Public License as published by the Free Software - Foundation; either version 2.1, or (at your option) any later version. - - TALER is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License along with - TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> - -.. target audience: developer, core developer - -.. _libeufin-bank-api: - -================= -Libeufin Bank API -================= - -.. contents:: Table of Contents - -Introduction ------------- - -The Libeufin bank provides a minimal core banking system. In addition to that, -it provides features for local/regional currencies. - -Authentication --------------- - -Some requests require the client to authenticate via HTTP Basic auth (RFC 7617) -or using a bearer token which can be obtained or refreshed from the -``/accounts/$USERNAME/token`` endpoint. -When using Basic authentication, the user-id must be the libeufin-bank -username, and the password the password for the corresponding user. - -Another way to obtain a login token is by manually configuring it for certain -endpoints. For example, the exchange could give an auditor read-only access to -the taler-wire-gateway facade via such a manually configured access token. - -The ``admin`` user is a special, hard-coded username. Some requests require the -client to authenticate as the admin. - -.. http:post:: /accounts/$USERNAME/token - - See :ref:`DD 48 token endpoint <dd48-token>`. - - -Libeufin Bank Web UI --------------------- - -The web UI for the libeufin-bank is typically served under ``/``. - -Config ------- - -.. http:get:: /config - - **Response:** - - .. ts:def:: Config - - interface Config { - // Name of this API, always "libeufin-bank". - name: string; - - // API version in the form $n:$n:$n - version: string; - - // If 'true', the server provides local currency - // conversion support. - // If missing or false, some parts of the API - // are not supported and return 404. - have_cashout?: boolean; - - // Fiat currency. That is the currency in which - // cash-out operations ultimately wire money. - // Only applicable if have_cashout=true. - fiat_currency?: string; - } - - -Account Management ------------------- - -.. _libeufin-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 - username: string; - - // Password. - password: string; - - // Legal name of the account owner - name: string; - - // Defaults to false. - is_public?: boolean; - - // Is this 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 transactions. - // Currently only used for cashouts. - // If missing, cashouts will fail. - // In the future, might be used for other transactions - // as well. - challenge_contact_data?: ChallengeContactData; - - // 'payto' address pointing a bank account - // external to the libeufin-bank. - // Payments will be sent to this bank account - // when the user wants to convert the local currency - // back to fiat currency outside libeufin-bank. - cashout_payto_uri?: string; - - // Internal payto URI of this bank account. - // Used mostly for testing. - internal_payto_uri?: string; - } - - .. ts:def:: ChallengeContactData - - interface ChallengeContactData { - - // E-Mail address - email?: EmailAddress; - - // Phone number. - phone?: PhoneNumber; - } - - - **Response:** - - :http:statuscode:`204 No content`: - The account was successfully created. - :http:statuscode:`400 Bad request`: - Input data was invalid. For example, the client specified a invalid - phone number or e-mail address. - :http:statuscode:`403 Forbidden`: - The response should indicate one of the following reasons. - - * A reserved username was attempted, like ``admin`` or ``bank``. - * An unauthorized user tried to create the account - - :http:statuscode:`409 Conflict`: - The internal account payto URI or username already exists. - -.. _delete-account: - -.. http:delete:: /accounts/$USERNAME - - Delete the account whose username is ``$USERNAME``. The deletion - succeeds only if the balance is *zero*. - - **Response:** - - :http:statuscode:`204 No content`: - The account was successfully deleted. - :http:statuscode:`403 Forbidden`: - The request specified a reserved internal username, like - ``admin`` or ``bank``. - :http:statuscode:`404 Not found`: - The username was not found. - :http:statuscode:`412 Precondition failed`: - The balance was not zero. - - -.. _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 transactions. - // Currently only used for cashouts. - // If missing, cashouts will fail. - // In the future, might be used for other transactions - // as well. - challenge_contact_data?: ChallengeContactData; - - // 'payto' address pointing a bank account - // external to the libeufin-bank. - // Payments will be sent to this bank account - // when the user wants to convert the local currency - // back to fiat currency outside libeufin-bank. - cashout_address?: string; - - // Legal name associated with $username. - // When missing, the old name is kept. - name?: string; - - // If present, change the is_exchange configuration. - // See `RegisterAccountRequest` - is_exchange?: boolean; - } - - **Response:** - - :http:statuscode:`204 No content`: - Operation successful. - - :http:statuscode:`403 Forbidden`: - The rights to change ``$USERNAME`` are not sufficient. - That includes the case where a correctly authenticated - user tries to change their legal name. It also - includes the case where 'admin' tries to change its - own account. - - :http:statuscode:`404 Not found`: - The account pointed by ``$USERNAME`` - was not found. - - -.. _account-password-reconfig: - -.. http:patch:: /accounts/$USERNAME/auth - - Allows changing the account's password. - - **Request:** - - .. ts:def:: AccountPasswordChange - - interface AccountPasswordChange { - - // New password. - new_password: string; - } - - **Response:** - - :http:statuscode:`204 No content`: - Operation successful. - - -.. _account-list: - -.. http:get:: ${BANK_API_BASE_URL}/public-accounts - - Show those accounts whose histories are publicly visible. For example, - accounts from donation receivers. As such, this request is unauthenticated. - - **Response** - - **Details** - - .. ts:def:: PublicAccountsResponse - - interface PublicAccountsResponse { - public_accounts: PublicAccount[]; - } - - .. ts:def:: PublicAccount - - interface PublicAccount { - payto_uri: string; - - balance: Balance; - - // The account name (=username) of the - // libeufin-bank account. - account_name: string; - } - - -.. 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 filter_name: *Optional.* - Pattern to filter on the account 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. - - **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:`403 Forbidden`: - A ordinary user invoked this call. - - **Details:** - - .. ts:def:: ListBankAccountsResponse - - interfaces ListBankAccountsResponse { - accounts: AccountMinimalData[]; - } - - .. ts:def:: Balance - - interface Balance { - amount: Amount; - credit_debit_indicator: "credit" | "debit"; - } - - .. ts:def:: AccountMinimalData - - interface AccountMinimalData { - // Username - username: string; - - // Legal name of the account owner. - name: string; - - // current balance of the account - balance: Balance; - - // Number indicating the max debit allowed for the requesting user. - debit_threshold: Amount; - } - -.. _libeufin-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 libeufin-bank responds with an `AccountData` object. - - **Details:** - - .. ts:def:: AccountData - - interface AccountData { - // Legal name of the account owner. - name: string; - - // Available balance on the account. - balance: Balance; - - // payto://-URI of the account. - payto_uri: string; - - // Number indicating the max debit allowed for the requesting user. - debit_threshold: Amount; - - contact_data?: ChallengeContactData; - - // 'payto' address pointing the bank account - // where to send cashouts. 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; - } - -Transactions ------------- - -.. http:get:: ${BANK_API_BASE_URL}/accounts/${account_name}/transactions - - Retrieve a subset of transactions related to $account_name. Without - query parameters, it returns the last 5 transactions. - - The list of returned transactions is determined by a row ID *starting point* - and a signed non-zero integer *delta*: - - * If *delta* is positive, return a list of up to *delta* transactions (all matching - the filter criteria) strictly **after** the starting point. The transactions are sorted - in **ascending** order of the row ID. - * If *delta* is negative, return a list of up to *-delta* transactions (all matching - the filter criteria) strictly **before** the starting point. The transactions are sorted - in **descending** order of the row ID. - - If *starting point* is not explicitly given, it defaults to: - - * A value that is **smaller** than all other row IDs if *delta* is **positive**. - * A value that is **larger** than all other row IDs if *delta* is **negative**. - - **Request** - - :query long_poll_ms: Optional number to express how many milliseconds the server - should wait for at least one result to be shown. If not given, the server - responds immediately, regardless of the result. - :query start: *Optional.* - Row identifier to explicitly set the *starting point* of the query. - :query delta: - The *delta* value that determines the range of the query. - - **Response** - - .. ts:def:: BankAccountTransactionsResponse - - interface BankAccountTransactionsResponse { - transactions: BankAccountTransactionInfo[]; - } - -.. http:get:: ${BANK_API_BASE_URL}/accounts/${account_name}/transactions/${transaction_id} - - **Response** - - Retrieve the transaction whose identifier is ``transaction_id``, - in the following format: - - .. ts:def:: BankAccountTransactionInfo - - interface BankAccountTransactionInfo { - creditor_payto_uri: string; - debtor_payto_uri: string; - - amount: Amount; - direction: "debit" | "credit"; - - subject: string; - - // Transaction unique ID. Matches - // $transaction_id from the URI. - row_id: number; - date: Timestamp; - } - - -.. http:post:: ${BANK_API_BASE_URL}/accounts/${account_name}/transactions - - Create a new transaction where the bank account with the label ``account_name`` is **debited**. - - **Request** - - .. ts:def:: BankAccountTransactionCreate - - interface CreateBankAccountTransactionCreate { - - // 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; - } - - **Response** - - :http:statuscode:`200 OK`: - the transaction has been created. - - :http:statuscode:`400 Bad Request`: - the request was invalid or the payto://-URI used unacceptable features. - - -Taler Withdrawals ------------------ - -.. http:post:: ${BANK_API_BASE_URL}/accounts/${account_name}/withdrawals - - Create a withdrawal operation, resulting in a ``taler://withdraw`` URI. - - **Request** - - .. ts:def:: BankAccountCreateWithdrawalRequest - - interface BankAccountCreateWithdrawalRequest { - // Amount to withdraw. - amount: Amount; - } - - **Response** - - .. ts:def:: BankAccountCreateWithdrawalResponse - - interface BankAccountCreateWithdrawalResponse { - // ID of the withdrawal, can be used to view/modify the withdrawal operation. - withdrawal_id: string; - - // URI that can be passed to the wallet to initiate the withdrawal. - taler_withdraw_uri: string; - } - - :http:statuscode:`403 Forbidden`: - The operation was rejected due to insufficient funds. - -.. http:get:: ${BANK_API_BASE_URL}/accounts/${account_name}/withdrawals/${withdrawal_id} - - Query the status of a withdrawal operation. - - **Response** - - **Details** - - .. ts:def:: BankAccountGetWithdrawalResponse - - interface BankAccountGetWithdrawalResponse { - // Amount that will be withdrawn with this withdrawal operation. - amount: Amount; - - // Was the withdrawal aborted? - aborted: boolean; - - // Has the withdrawal been confirmed by the bank? - // The wire transfer for a withdrawal is only executed once - // both ``confirmation_done`` is ``true`` and ``selection_done`` is ``true``. - confirmation_done: boolean; - - // Did the wallet select reserve details? - selection_done: boolean; - - // Reserve public key selected by the exchange, - // only non-null if ``selection_done`` is ``true``. - selected_reserve_pub: string | null; - - // Exchange account selected by the wallet, or by the bank - // (with the default exchange) in case the wallet did not provide one - // through the Integration API. - selected_exchange_account: string | null; - } - - -.. http:post:: ${BANK_API_BASE_URL}/accounts/${account_name}/withdrawals/${withdrawal_id}/abort - - Abort a withdrawal operation. Has no effect on an already aborted withdrawal operation. - - :http:statuscode:`200 OK`: The withdrawal operation has been aborted. The response is an empty JSON object. - :http:statuscode:`409 Conflict`: The reserve operation has been confirmed previously and can't be aborted. - - -.. http:post:: ${BANK_API_BASE_URL}/accounts/${account_name}/withdrawals/${withdrawal_id}/confirm - - Confirm a withdrawal operation. Has no effect on an already confirmed withdrawal operation. - This call is responsible of wiring the funds to the exchange. - - **Response** - - :http:statuscode:`200 OK`: - The withdrawal operation has been confirmed. The response is an empty JSON object. - :http:statuscode:`409 Conflict`: - The withdrawal has been aborted previously and can't be confirmed. - :http:statuscode:`422 Unprocessable Entity` (New): - The withdraw operation cannot be confirmed because no exchange and reserve public key selection happened before. - -Cashouts --------- - -.. _account-cashout: - -.. http:post:: /accounts/$USERNAME/cashouts - - Initiates a conversion to fiat currency. The external - bank account to be - credited is the one specified at registration time via the - *cashout_address* parameter. The libeufin-bank internal account - is specified via ``$USERNAME``. - The bank sends a TAN to the customer to let them confirm the - operation. The request is only available to ordinary users, not - to the administrator. - - .. note:: - - Consult the `cashout rates call <cashout-rates_>`_ to learn - about any applicable fee or exchange rate. - - .. note:: - - FIXME: Eventually, the env variables will be replaced with - configuration settings. - - To test this operation without relying on any SMS/E-mail provider, - Libeufin offers two methods: defining an environment variable called - ``LIBEUFIN_CASHOUT_TEST_TAN`` or specifying the value ``file`` to - the ``tan_channel`` field of the `request object <cashout-request_>`_. - Assuming ``LIBEUFIN_CASHOUT_TEST_TAN`` is set to *T*, every */confirm* - operation can use *T* as the TAN. Setting instead the ``tan_channel`` - field to ``file`` will cause the server to (over)write every TAN to - ``/tmp/libeufin-cashout-tan.txt``. If both are used, the environment - variable takes the precedence. - - - **Request:** - - `CashoutRequest <cashout-request_>`_ - - .. ts:def:: TanChannel - - enum TanChannel { - SMS = "sms", - EMAIL = "email", - FILE = "file" - } - - .. _cashout-request: - - .. ts:def:: CashoutRequest - - interface CashoutRequest { - - // Optional subject to associate to the - // cashout operation. This data will appear - // as the incoming wire transfer subject in - // the user's external bank account. - subject?: string; - - // That is the plain amount that the user specified - // to cashout. Its $currency is the (regional) currency of the - // libeufin-bank instance. - amount_debit: Amount; - - // That is the amount that will effectively be - // transferred by the bank to the user's bank - // account, that is external to the regional currency. - // It is expressed in the fiat currency and - // is calculated after the cashout fee and the - // exchange rate. See the /cashout-rates 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; - - // Which channel the TAN should be sent to. If - // this field is missing, it defaults to SMS. - // The default choice prefers to change the communication - // channel respect to the one used to issue this request. - tan_channel?: TanChannel; - } - - **Response:** - - :http:statuscode:`202 Accepted`: - The cashout request was correctly created and - the TAN authentication now is pending. - This returns the `CashoutPending` response. - :http:statuscode:`409 Conflict`: - The user did not share any contact data where to send the TAN, - the account does not have sufficient funds, or the - exchange rate was calculated incorrectly by the client. - :http:statuscode:`503 Service unavailable`: - The bank does not support the TAN channel for this operation. - - **Details:** - - .. ts:def:: CashoutPending - - interface CashoutPending { - // ID identifying the operation being created - // and now waiting for the TAN confirmation. - cashout_id: string; - } - - -.. _cashout-abort: - -.. http:post:: /accounts/$USERNAME/cashouts/$CASHOUT_ID/abort - - Aborts the ``$CASHOUT_ID`` operation. - - **Response:** - - :http:statuscode:`204 No content`: - ``$CASHOUT_ID`` was found in the *pending* state - and got successfully aborted. - :http:statuscode:`404 Not found`: - ``$CASHOUT_ID`` is not found. Note: that happens - also when ``$CASHOUT_ID`` got aborted before this request. - :http:statuscode:`409 Conflict`: - ``$CASHOUT_ID`` was already confirmed. - - -.. _cashout-confirm: - -.. http:post:: /accounts/$USERNAME/cashouts/$CASHOUT_ID/confirm - - Confirms the ``$CASHOUT_ID`` operation by providing its - TAN. The request should still be authenticated with - the users credentials. - - **Request:** - - .. ts:def:: CashoutConfirm - - interface CashoutConfirm { - // the TAN that confirms $CASHOUT_ID. - tan: string; - } - - **Response:** - - :http:statuscode:`204 No content`: - The request succeeded, either for the first time, or it already was - confirmed previously (idempotency!). - :http:statuscode:`403 Forbidden`: - Wrong TAN or bad credentials. - :http:statuscode:`404 Not found`: - ``$CASHOUT_ID`` is not found. Note: that happens - also when ``$CASHOUT_ID`` got aborted before this request. - :http:statuscode:`409 Conflict`: - The user changed their cash-out address between the creation and the confirmation of ``$CASHOUT_ID``. - - -.. _cashout-rates: - -.. http:get:: /cashout-rate - - This public endpoint allows clients to calculate - the exchange rate between the regional currency - and the external 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-out operations. - At least one of the two query parameters must be provided. If both are - given, then the server checks their correctness. Amounts must include the - currency. - - **Request:** - - :query amount_debit: this is the amount that the user will get - deducted from their regional bank account. - - :query amount_credit: this is the amount that the user will receive - in their fiat bank account. - - **Response:** - - .. 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:statuscode:`200 Ok`: - Response is a `CashoutConversionResponse`. - :http:statuscode:`400 Bad request`: - Both parameters have been provided and the calculation is not correct, - or none of them has been provided. - :http:statuscode:`404 Not found`: - The server does not support local currency conversion. - - -.. _circuit-cashouts: - -.. http:get:: /accounts/$USERNAME/cashouts - - Returns the list of all the (pending and confirmed) cash-out operations - for an account. - - **Response:** - - .. ts:def:: Cashouts - - interface Cashouts { - // Every string represents a cash-out operation ID. - cashouts: CashoutInfo[]; - } - - .. ts:def:: CashoutInfo - - interface CashoutInfo { - cashout_id: string; - status: "pending" | "confirmed"; - } - - :http:statuscode:`200 OK`: - At least one cash-out operation was found. - - :http:statuscode:`204 No Content`: - No cash-out operations were found at the bank - -.. http:get:: /cashouts - - Returns the list of all the (pending and confirmed) cash-out operations - for **all** accounts. - - Typically can only be used by the administrators. - - .. note:: - - We might want to add a filter in the future to only - query pending cashout operations. - - **Response:** - - .. ts:def:: GlobalCashouts - - interface GlobalCashouts { - // Every string represents a cash-out operation ID. - cashouts: { cashout_id: string, username: string}[]; - } - - .. ts:def:: GlobalCashoutInfo - - interface GlobalCashoutInfo { - cashout_id: string; - username: string; - status: "pending" | "confirmed"; - } - - :http:statuscode:`200 OK`: - At least one cash-out operation was found. - - :http:statuscode:`204 No Content`: - No cash-out operations were found at the bank - -.. _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:** - - `CashoutStatusResponse <cashout-status_>`_ - - .. _cashout-status: - - .. ts:def:: CashoutStatus - - interface CashoutStatusResponse { - status: "pending" | "confirmed"; - - // Amount debited to the internal - // regional currency bank account. - amount_debit: Amount; - - // Amount credited to the external bank account. - amount_credit: Amount; - - // Transaction subject. - subject: string; - - // Fiat bank account that will receive the cashed out amount. - // Specified as a payto URI. - credit_payto_uri: string; - - // Time when the cashout was created. - creation_time: Timestamp; - - // Time when the cashout was confirmed via its TAN. - // Missing when the operation wasn't confirmed yet. - confirmation_time?: Timestamp; - } - - **Response:** - - :http:statuscode:`404 Not found`: - The cashout operation was not found. - Aborted cashout operations will also not be found. - -Taler Bank Integration API --------------------------- - -.. 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. - -Taler Wire Gateway API ----------------------- - -.. 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_exchange=true``. - -Taler Revenue API ----------------------- - -.. http:any:: /accounts/$USERNAME/taler-revenue/* - - All endpoints under this prefix are specified - by the :doc:`GNU Taler Revenue API </core/api-bank-revenue>`. - -EBICS Host ----------- - -The Taler bank can be configured to serve bank account transactions and allow -payment initiations via the EBICS protocol. - -This is an optional feature, not all implementations of the API support it. - -.. http:post:: /ebicshost - - EBICS base URL. This URL allows clients to make EBICS requests to one of - the configured EBICS hosts. - diff --git a/core/index-bank-apis.rst b/core/index-bank-apis.rst @@ -30,7 +30,7 @@ Bank RESTful APIs api-bank-wire api-bank-revenue api-bank-integration - api-libeufin-bank + api-corebank .. toctree::