14.12. Create a local currency (experimental)

This LibEuFin tutorial shows how to manage a bank account in the local currency, and how to convert assets from the local to the fiat currency. Such conversion is called cash-out.

This tutorial is based on the Circuit API, and more general information about libEufin can be found in the How-To page.

The first step is building LibEuFin.

If the installation succeeded, configure Sandbox (= the service acting as the bank) with the following command.

$ export LIBEUFIN_SANDBOX_DB_CONNECTION=jdbc:sqlite:/tmp/libeufin.sqlite3
$ libeufin-sandbox config --currency NB --without-registrations default


The --without-registrations option allows only the administrator to add new accounts. Without this option, other APIs may offer unrestricted registrations.

All the commands mentioned in the following steps support a --help option that lists all the available options under the related command.

If the configuration step succeeded, Sandbox should be ready to serve the bank for a currency named NB.

In following step, we launch Sandbox by setting the administrator password as secret.


The following command launches Sandbox so that it writes TANs on the filesystem to ease the cash-out operations without relying on an actual e-mail or SMS provider.

$ libeufin-sandbox serve

Sandbox should now be listening on the port 5000. Check it with:

$ curl http://localhost:5000

If Sandbox is correctly running, it should respond with a greeting message. At this point, the administrator can add a new merchant to the bank with the following command.

export LIBEUFIN_SANDBOX_URL=http://localhost:5000/

libeufin-cli \
  sandbox \
  demobank \
  circuit-register \
    --name "Circuit Shop" \
    --username circuit-shop \
    --cashout-address payto://iban/CH463312 \
    --internal-iban INT940993

If the previous step succeeded, the merchant should have access to their bank account with the circuit-shop username and shop-secret password.

Check it by asking the merchant balance with the following command. The two environment variables LIBEUFIN_SANDBOX_USERNAME and LIBEUFIN_SANDBOX_PASSWORD instruct the CLI to authenticate as the merchant.


libeufin-cli sandbox demobank info --bank-account circuit-shop

The expected response looks like the following one:

  "balance" : {
    "amount" : "NB:0",
    "credit_debit_indicator" : "credit"
  "paytoUri" : "payto://iban/SANDBOXX/INT940993?receiver-name=Circuit+Shop",
  "iban" : "INT940993"

In the following example, the merchant creates a cash-out operation, trying to convert 1 NB back to the fiat currency. The --amount-debit option takes the amount that the merchant wants to be debited in their local currency bank account, whereas the --amount-credit option is the calculation of the conversion rates as expected by the merchant. The two values will be checked by the bank along this request, to make sure that both parties agree.


The current version has a fixed 0.95 conversion rate for cashing out. Future version will make this value configurable.

libeufin-cli \
  sandbox \
  demobank \
  circuit-cashout \
    --amount-debit=NB:1 \
    --amount-credit=FIAT:0.95 \

If the previous command succeeded, it returned a JSON looking like the following, although most likely having a different UUID.

  "uuid" : "de12389b-e477-4a0c-829e-f779c1cfb3a0"

The uuid represents the cash-out operation being just created and waiting to be confirmed with a TAN.


The current version provides only the local currency side of such operation. In other words, the merchant can now only see a deduction on their local currency bank account but no incoming payment in their fiat bank account. Future versions will implement this.

Confirm now the cash-out operation by sending to the bank the TAN found in the file /tmp/libeufin-cashout-tan.txt. Assuming that the TAN for it is WXYZ, the next command will confirm it to the bank (please, use your UUID).

libeufin-cli \
  sandbox demobank circuit-cashout-confirm \
    --uuid de12389b-e477-4a0c-829e-f779c1cfb3a0 \
    --tan WXYZ

Check now that the cash-out operation appears as a outgoing transaction for the merchant:

libeufin-cli \
  sandbox demobank list-transactions \
    --bank-account circuit-shop

The expected output should contain one line like the following. That witnesses that the cash-out was correctly confirmed and scheduled to be transferred to the fiat account.

"subject" : "Cash-out of NB:1 to FIAT:0.95"

The next commands show how to delete one account from the local currency circuit. For the deletion to succeed, the account must have a balance of zero NB. Because of the cash-out operation, the merchant has now -1 NB to their account, therefore the deletion will fail. Check it, as the administrator, with the following command


libeufin-cli \
  sandbox demobank \
  circuit-delete-account --username circuit-shop

The expected output is:

Unexpected response status: 412
Response: {
  "error" : {
    "type" : "sandbox-error",
    "description" : "Account circuit-shop doesn't have zero balance.  Won't delete it"

The bank may now award 1 NB to the merchant to bring their balance to zero and finally delete the account. With the following command, the administrator awards 1 NB to the merchant.

libeufin-cli \
  sandbox demobank new-transaction \
    --bank-account admin \
    --payto-with-subject "payto://iban/SANDBOXX/INT940993?message=bring-to-zero" \
    --amount NB:1

Check if the balance returned to zero with this command, and try again to delete the account like already done

Now the deletion command should have succeeded! Try to ask the balance again, and expect one error like the following:

  "error" : {
    "type" : "util-error",
    "description" : "Customer 'circuit-shop' not found"

14.12.1. E-mail or SMS TAN setup

SMS and E-mail TANs get sent via commands that are invoked by the Sandbox. Sandbox learns about those commands via optional parameters to the serve command.


Future versions will allow setting the external commands via the configuration; follow #7527.

Hence, starting Sandbox as shown in the following commands is the only requirement to use the aforementioned TAN channels.

For the SMS TAN:

libeufin-sandbox serve --sms-tan sms_provider_command

Alternatively, for the e-mail TAN:

libeufin-sandbox serve --email-tan email_provider_command

Both commands will be passed the TAN to STDIN and the target phone number / e-mail address as their first command line argument.


The way the invoked commands interact with their providers is out of the Sandbox scope.

Finally, Libeufin ships two TAN commands as example. The e-mail command relies on GNU mail and the SMS command on the service offered by telesign.com. Check contrib/libeufin-tan-sms.sh and contrib/libeufin-tan-email.sh in the Libeufin repository.