.. target audience: developer, core developer .. _sandbox-api: Sandbox API ########### Sandbox emulates a minimal bank, to provide EBICS access to test `Taler `_. The top-level API defines two main groups: `demobanks `_ and `legacy `_. Currently, `error types `_ are common to both groups. Demobanks ========= Sandbox is designed to allow multiple *demobanks* being hosted, where every demobank can have its own configuration (including a different currency). A demobank has a name, although currently only one demobank, named ``default``, is supported. Such demobank activates the API segment ``/demobanks/default``, under which several APIs are then served. The following sections describe all such APIs. Circuit API ^^^^^^^^^^^ This API offers to manage a selected group of users who act as businesses for a local currency. Policies to disincentivize cashout operations may also apply, making therefore this setup a *circuit* within a wider traditional currency. For brevity, the list of response statuses for each endpoint may not be exhaustive. .. note:: This API requires to **disable** ordinary registrations in the configuration, to avoid other APIs from circumventing this registration policy. See ``libeufin-sandbox config --help``. The following endpoints are served under ``/demobanks/default/circuit-api``. Accounts -------- .. http:post:: /accounts Create a new bank account. Only the administrator is allowed. **Request:** .. ts:def:: CircuitAccountRequest interface CircuitAccountRequest { // Username username: string; // Password. password: string; // Addresses where to send the TAN. If // this field is missing, then the cashout // won't succeed. contact_data: CircuitContactData; // Legal subject owning the account. name: string; // 'payto' address pointing the bank account // where to send payments, in case the user // wants to convert the local currency back // to fiat. cashout_address: string; // IBAN of this bank account, which is therefore // internal to the circuit. Randomly generated, // when it is not given. internal_iban?: string; } .. ts:def:: CircuitContactData interface CircuitContactData { // E-Mail address email?: string; // Phone number. phone?: string; } **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 institutional username was attempted, like ``admin`` or ``bank``. * A non admin user tried the operation. :http:statuscode:`409 Conflict`: At least one registration detail was not available, the error message should inform about it. .. http:delete:: /accounts/$username Delete the account whose username is ``$username``. The deletion succeeds only if the balance is *zero*. Only the administrator is allowed. **Response:** :http:statuscode:`204 No content`: The account was successfully deleted. :http:statuscode:`403 Forbidden`: The administrator specified a institutional 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. .. http:patch:: /accounts/$username Allows the administrator and the user to reconfigure the account data of ``$username``. **Request:** .. ts:def:: CircuitAccountReconfiguration interface CircuitAccountReconfiguration { // Addresses where to send the TAN. If // this field is missing, then the cashout // won't succeed. contact_data?: CircuitContactData; // 'payto' address pointing the bank account // where to send payments, in case the user // wants to convert the local currency back // to fiat. cashout_address: string; } **Response:** :http:statuscode:`204 No content`: Operation successful. :http:statuscode:`404 Not found`: The account pointed by ``$username`` was not found. .. http:patch:: /accounts/$username/auth Allows administrators *and* ordinary users to change the account's password. **Request:** .. ts:def:: AccountPasswordChange interface AccountPasswordChange { // New password. new_password: string; } **Response:** :http:statuscode:`204 No content`: Operation successful. .. http:get:: /accounts Obtains a list of all the accounts registered at the bank. It returns only the information that this API handles, without any balance or transactions list. The :doc:`Access API ` offers that. This request is only available to the administrator. **Response:** `CircuitAccounts `_ .. _circuit-accounts: .. ts:def:: CircuitAccounts interfaces CircuitAccounts { customers: CircuitAccountMinimalData[]; } .. ts:def:: CircuitAccountMinimalData interface CircuitAccountMinimalData { // Username username: string; // Legal subject owning the account. name: string; } .. http:get:: /accounts/$username Obtains information relative to the account owned by ``$username``. The request is available to the administrator and ``$username`` itself. **Response:** .. ts:def:: CircuitAccountData interface CircuitAccountData { // Username username: string; // IBAN hosted at Libeufin Sandbox iban: string; contact_data: CircuitContactData; // Legal subject owning the account. name: string; // 'payto' address pointing the bank account // where to send cashouts. cashout_address: string; } :http:statuscode:`403 Forbidden`: The user is not allowed. Cashouts -------- .. http:post:: /cashouts Initiates a conversion to fiat currency. The target account is the one specified at registration time. The account to be debited is extracted from the authentication credentials. 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 `_ to learn about any applicable fee or exchange rate. **Request:** `CashoutRequest `_ .. ts:def:: TanChannel enum TanChannel { SMS = "sms", EMAIL = "email" } .. _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 circuit currency. 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 circuit. // It is expressed in the fiat currency and // is calculated after the cashout fee and the // exchange rate. See the /cashout-rates call. 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:** .. ts:def:: CashoutPending interface CashoutPending { // UUID identifying the operation being created // and now waiting for the TAN confirmation. uuid: string; } :http:statuscode:`202 Accepted`: The cashout request was correctly created and the TAN authentication now is pending. :http:statuscode:`400 Bad request`: The exchange rate was incorrectly applied. :http:statuscode:`403 Forbidden`: A institutional user (``admin`` or ``bank``) tried the operation. :http:statuscode:`409 Forbidden`: The user did not share any contact data where to send the TAN. :http:statuscode:`412 Precondition failed`: The account does not have sufficient funds. :http:statuscode:`503 Service unavailable`: The bank does not support the TAN channel for this operation. .. http:post:: /cashouts/$cashoutId/abort Aborts the ``$cashoutId`` operation. Original author *and* admin are both allowed. **Response:** :http:statuscode:`204 No content`: ``$cashoutId`` was found in the *pending* state and got successfully aborted. :http:statuscode:`404 Not found`: ``$cashoutId`` is not found. Note: that happens also when ``$cashoutId`` got aborted before this request. :http:statuscode:`412 Precondition failed`: ``$cashoutId`` was already confirmed. .. http:post:: /cashouts/$cashoutId/confirm Confirms the ``$cashoutId`` operation by accepting its TAN. The request should still be authenticated with the users credentials. Only the original author is allowed. **Request:** .. ts:def:: CashoutConfirm interface CashoutConfirm { // the TAN that confirms $cashoutId. tan: string; } **Response:** :http:statuscode:`204 No content`: ``$cashoutId`` was found in the *pending* state and got successfully confirmed. :http:statuscode:`403 Forbidden`: wrong TAN. :http:statuscode:`404 Not found`: ``$cashoutId`` is not found. Note: that happens also when ``$cashoutId`` got aborted before this request. :http:statuscode:`409 Conflict`: A institutional user (``admin`` or ``bank``) tried the operation. :http:statuscode:`412 Precondition failed`: ``$cashoutId`` was already confirmed. .. _cashout-rates: .. http:get:: /config **Response:** .. ts:def:: Config interface Config { // Name of this API, always "circuit". name: string; // API version in the form $n:$n:$n version: string; // Contains ratios and fees related to buying // and selling the circuit currency. ratios_and_fees: RatiosAndFees; } .. ts:def:: RatiosAndFees interface RatiosAndFees { // Exchange rate to buy the circuit currency from fiat. buy_at_ratio: float; // Exchange rate to sell the circuit currency for fiat. sell_at_ratio: float; // Fee to subtract after applying the buy ratio. buy_in_fee: float; // Fee to subtract after applying the sell ratio. sell_out_fee: float; } Example. Given a circuit currency CC, a fiat currency FC, a *sell_at_ratio* = 0.9 and *sell_out_fee* = 0.03, selling 10 CC would result in the following FC: (10 * 0.9) - 0.03 = 8.97 FC. On the other hand, given *buy_at_ratio* = 1.1 and *buy_in_fee* = 0.01, a user wanting to spend 10 FC to buy the CC would result in the following CC: (10 * 1.1) - 0.01 = 10.99 CC. .. note:: the terms 'sell out' and 'cashout' may be used interchangeably. .. http:get:: /cashouts/$cashoutId Informs about the status of the ``$cashoutId`` operation. The request is available to the administrator and the original author. **Response:** `CashoutStatusResponse `_ .. _cashout-status: .. ts:def:: CashoutStatus interface CashoutStatusResponse { status: CashoutStatus; } .. ts:def:: CashoutStatus enum CashoutStatus { // The payment was initiated after a valid // TAN was received by the bank. CONFIRMED = "confirmed", // The cashout was created and now waits // for the TAN by the author. PENDING = "pending", } **Response:** :http:statuscode:`404 Not found`: The cashout operation was not found. That is *also* the case of ``$cashoutId`` being an aborted operation. Access API ^^^^^^^^^^ Every endpoint is served under ``/demobanks/default/access-api``. See :doc:`/core/api-bank-access`. This API allows users to access their bank accounts and trigger Taler withdrawals. Integration API ^^^^^^^^^^^^^^^ Every endpoint is served under ``/demobanks/default/integration-api``. See :doc:`/core/api-bank-integration`. This API handles the communication with Taler wallets. Taler Wire Gateway API ^^^^^^^^^^^^^^^^^^^^^^ Served under ``/demobanks/default/taler-wire-gateway``. Currently, only the :ref:`admin/add-incoming ` endpoint is implemented. This endpoint allows testing, but the rest of this API does never involve the Sandbox. EBICS API ^^^^^^^^^ .. _demobank-create-ebics-subscriber: .. http:post:: /demobanks/default/ebics/subscribers Allows (only) the *admin* user to associate a bank account to a EBICS subscriber. If the latter does not exist, it is created. **Request:** .. ts:def:: SubscriberRequest interface SubscriberRequest { // hostID hostID: string; // userID userID: string; // partnerID partnerID: string; // systemID, optional. systemID: string; // Label of the bank account to associate with // this subscriber. demobankAccountLabel: string; } .. note:: The following endpoints are **not** served under the ``/demobank/default`` segment. Legacy API ========== This was the first API offered by Sandbox. It is used in some test cases. One is hosted at the Wallet repository; other MAY as well exist. Except of the main EBICS handler located at "/ebicsweb", all the EBICS calls have to authenticate the 'admin' user via the HTTP basic auth scheme. EBICS Hosts ^^^^^^^^^^^ .. http:post:: /admin/ebics/hosts Create a new EBICS host. **Request:** .. ts:def:: EbicsHostRequest interface EbicsHostRequest { // Ebics version. hostID: string; // Name of the host. ebicsVersion: string; } .. http:get:: /admin/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. ebicsHosts: string[]; } .. http:post:: /admin/ebics/hosts/$hostID/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. EBICS Subscribers ^^^^^^^^^^^^^^^^^ .. http:post:: /admin/ebics/bank-accounts Associates a new bank account to an existing subscriber. **Request:** .. ts:def:: BankAccountRequest interface BankAccountRequest { // Ebics subscriber subscriber: { userID: string; partnerID: string; systemID: string; }; // IBAN iban: string; // BIC bic: string; // human name name: string; // bank account label label: string; } .. http:get:: /admin/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 userID: string; // partnerID partnerID: string; // hostID hostID: string; // Label of the bank account // associated with this Ebics subscriber. demobankAccountLabel: string; } .. http:post:: /admin/ebics/subscribers Create a new EBICS subscriber without associating a bank account to it. This call is **deprecated**. Follow `this page `_ for updates over the EBICS management REST design. **Request:** .. ts:def:: SubscriberRequestDeprecated interface SubscriberRequestDeprecated { // hostID hostID: string; // userID userID: string; // partnerID partnerID: string; // systemID, optional. systemID: string; } Bank accounts ^^^^^^^^^^^^^ The access to a particular bank account is granted either to the owner or to admin, via the HTTP basic auth scheme. A 'owner' is a registered customer, who is identified by a username. The registration of customers is offered via the :doc:`/core/api-bank-access`. .. note:: The current version allows only one bank account per customer, where the bank account name (also called 'label') equals the owner's username. .. http:get:: /admin/bank-accounts Give summary of all the bank accounts. Only admin allowed. **Response:** .. ts:def:: AdminBankAccount interface AdminBankAccount { // IBAN iban: string; // BIC bic: string; // human name name: string; // bank account label label: string; } .. http:get:: /admin/bank-accounts/$accountLabel Give information about a bank account. **Response:** .. ts:def:: AdminBankAccountBalance interface AdminBankAccountBalance { // Balance in the $currency:$amount format. balance: string; // IBAN of the bank account identified by $accountLabel iban: string; // BIC of the bank account identified by $accountLabel bic: string; // Mentions $accountLabel label: string; } .. http:post:: /admin/bank-accounts/$accountLabel Create bank account. Existing users without a bank account can request too. **Request:** :ts:type:`AdminBankAccount` Transactions ^^^^^^^^^^^^ .. http:get:: /admin/bank-accounts/$accountLabel/transactions Inform about all the transactions of one bank account. **Response:** .. ts:def:: AdminTransactions interface AdminTransactions { payments: AdminTransaction[]; } .. ts:def:: AdminTransaction interface AdminTransaction { // Label of the bank account involved in this payment. accountLabel: string; // Creditor IBAN creditorIban: string; // Debtor IBAN debtorIban: string; // UID given by one financial institute to this payment. // FIXME: clarify whether that can be also assigned by // the other party's institution. accountServicerReference: string; // ID of the Pain.001 that initiated this payment. paymentInformationId: string; // Unstructured remittance information. subject: string; // Date of the payment in the HTTP header format. date: string; // The number amount as a string. amount: string; // BIC of the creditor IBAN. creditorBic: string; // Legal name of the creditor. creditorName: string; // BIC of the debtor IBAN. debtorBic: string; // Legal name of the debtor. debtorName: string; // Payment's currency currency: string; // Have values 'credit' or 'debit' relative // to the requesting user. creditDebitIndicator: string; } .. http:post:: /admin/bank-accounts/$accountLabel/generate-transactions Generate one incoming and one outgoing transaction for the bank account identified by ``$accountLabel``. Only admin allowed. .. http:post:: /admin/bank-accounts/$accountLabel/simulate-incoming-transaction Book one incoming transaction for $accountLabel. The debtor (not required to be in the same bank) information is taken from the request. Only admin allowed. **Request:** .. ts:def:: AdminSimulateTransaction interface AdminSimulateTransaction { // Debtor IBAN. debtorIban: string; // Debtor BIC. debtorBic: string; // Debtor name. debtorName: string; // Amount number (without currency) as a string. amount: string; // Payment subject. subject: string; } .. http:post:: /admin/payments/camt Return the last camt.053 document from the requesting account. **Request** .. code-block:: tsref interface CamtParams { // label of the bank account being queried. bankaccount: string; // The Camt type to return. Only '53' is allowed // at this moment. type: number; } **Response** The last Camt.053 document related to the bank account mentioned in the request body. .. _error-types: ====== Errors ====== The JSON type coming along a non 2xx response is the following: .. ts:def:: SandboxError interface SandboxError { error: SandboxErrorDetail; } .. ts:def:: SandboxErrorDetail interface SandboxErrorDetail { // String enum classifying the error. type: ErrorType; // Human-readable error description. description: string; } .. ts:def:: ErrorType enum ErrorType { /** * This error can be related to a business operation, * a non-existent object requested by the client, or * even when the bank itself fails. */ SandboxError = "sandbox-error", /** * It is the error type thrown by helper functions * from the Util library. Those are used by both * Sandbox and Nexus, therefore the actual meaning * must be carried by the error 'message' field. */ UtilError = "util-error" }