diff options
-rw-r--r-- | core/api-libeufin-bank.rst | 985 | ||||
-rw-r--r-- | core/api-merchant.rst | 2 |
2 files changed, 986 insertions, 1 deletions
diff --git a/core/api-libeufin-bank.rst b/core/api-libeufin-bank.rst new file mode 100644 index 00000000..e1482864 --- /dev/null +++ b/core/api-libeufin-bank.rst @@ -0,0 +1,985 @@ +.. + 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). The user-id must be the libeufin-bank username, and the password the +password for the corresponding user. + +The ``admin`` user is a special, hard-coded username. Some requests require the +client to authenticate as the admin. + +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-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 subject owning the account. + name: string; + + is_public: 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_data?: ChallengeData; + + // '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; + } + + **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 subject owning the account. + name: string; + + // current balance of the account + balance: Balance; + + // Number indicating the max debit allowed for the requesting user. + debit_threshold: Amount; + } + + +.. 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 subject owning the account. + 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?: ContactData; + + // '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. + + **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 page: page number starting from 1. Page 1 has the latest transactions + and 1 is the default value. + :query size: how many transactions per page. It must be at least 1 and defaults to 5. + :query from_ms: Optional. Filters the results to transactions *from* (inclusively) this + timestamp in milliseconds + :query until_ms: Optional. Filters the results to transactions *until* (inclusively) this + timestamp in milliseconds + + **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_iban: string; + creditor_bic: string; // Optional + creditor_name: string; + + debtor_iban: string; + debtor_bic: string; + debtor_name: string; + + amount: number; + currency: string; + subject: string; + + // Transaction unique ID. Matches + // $transaction_id from the URI. + uid: string; + direction: "DBIT" | "CRDT"; + 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 +-------------------------- + +Every endpoint is served under ``/integration-api``. +See :doc:`/core/api-bank-integration`. This API handles the communication +with Taler wallets. + +Taler Wire Gateway API +---------------------- + +Served under ``/taler-wire-gateway``. Currently, +only the :ref:`admin/add-incoming <twg-admin-add-incoming>` endpoint +is implemented. This endpoint allows testing, but the rest of +this API does never involve the Sandbox. + +EBICS Host Management +--------------------- + +The libeufin-bank can be configured to serve the +bank account transactions via the EBICS protocol. + +The API for this is served under ``/ebics``. + +.. http:post:: /ebics/request + + EBICS base URL. This URL allows clients to make EBICS requests to one of + the configured EBICS hosts. + +.. http:post:: /ebics/hosts + + Create a new EBICS host. + + **Request:** + + .. ts:def:: EbicsHostRequest + + interface EbicsHostRequest { + + // Ebics version. + host_id: string; + + // Name of the host. + ebics_version: string; + } + + +.. http:get:: /ebics/hosts + + Shows the list of all the hosts in the system. + + **Response:** + + .. ts:def:: EbicsHostResponse + + interface EbicsHostResponse { + + // shows the host IDs that are active in the system. + // The Ebics version *is* missing, but it's still available + // via the HEV message. + ebics_hosts: string[]; + } + +.. http:post:: /ebics/hosts/$HOST_ID/rotate-keys + + Overwrite the bank's Ebics keys with random ones. This is entirely + meant for tests (as the Sandbox itself is) and no backup will be + produced along this operation. + +.. http:post:: /ebics/subscribers + + Allows (only) the ``admin`` user create an EBICS + subscriber associated to a bank account. + + **Request:** + + .. ts:def:: SubscriberRequest + + interface SubscriberRequest { + + // EBICS HostID + host_id: string; + + // EBICS UserID + user_id: string; + + // EBICS PartnerID + partner_id: string; + + // Optional EBICS SystemID + system_id?: string; + + // Username of the bank account to associate with + // this subscriber. + account_username: string; + } + + +.. http:get:: /ebics/subscribers + + Shows the list of all the subscribers in the system. + + **Response:** + + .. ts:def:: SubscribersResponse + + interface SubscribersResponse { + + subscribers: Subscriber[] + } + + .. ts:def:: Subscriber + + interface Subscriber { + + // userID + user_id: string; + + // partnerID + partner_id: string; + + // hostID + host_id: string; + + // Label of the bank account + // associated with this Ebics subscriber. + account_username: string; + } diff --git a/core/api-merchant.rst b/core/api-merchant.rst index d542b439..38865f05 100644 --- a/core/api-merchant.rst +++ b/core/api-merchant.rst @@ -3061,7 +3061,7 @@ to validate that a customer made a payment. // Counter for counter-based OTP devices. otp_ctr?: Integer; - } + } .. http:get:: [/instances/$INSTANCE]/private/otp-devices |