Welcome

Welcome to Monerium developer documentation. This is the place to learn about our blockchain smart contracts, functionality and API.

The Monerium money-as-a-service platform lets developers securely manage and automate the flow of money on and off blockchains

  • Real money on blockchains that you can send to anyone, anywhere at anytime without intermediaries. The money is also standardized to support all major blockchain wallets and smart contracts.
  • Monerium IBAN, a fiat gateway that enables you to seamlessly collect and send money between bank accounts and blockchain addresses.
  • Payment API that services can manage accounts, get payment notification and trigger outgoing payments.
  • Fully licensed. Monerium EMI is an electronic money institution, a European financial institution that is licensed to operate in the EEA and UK. We take care of the regulatory burden, so you can focus on creating the best possible product.

In this section we'll give a short introduction for those who are new to blockchain technology. You can also skip right ahead to the getting started section if you are familiar with blockchains, wallets and smart contracts.

DeFi - Decentralized Finance

Today's decentralized finance, or DeFi, movement on blockchains is disrupting and revolutionizing traditional finance.

DeFi goes way beyond cryptocurrencies and payments. Issuance and trading of assets, financing, micro-economies, insurance, taxes, accounting are just a few examples.

Blockchains, smart contracts, tokens and money

Let's take a couple steps back. DeFi, which is built on blockchains such as Ethereum, cuts out human middlemen and paperwork, and replaces them with smart contracts. These are computer programs that run on decentralized blockchains, meaning they're near-impossible to stop or censor. If I borrowed money from someone via a smart contract, the terms built into the contract have to be obliged.

Tokens are smart contracts that are created with properties that make them similar to certain financial products and services. This is also referred to as tokenization.

Stablecoins are tokens that are important to the DeFi ecosystem. Some are under the impression that all cryptocurrency is volatile. However, stablecoins are tokens designed to hold a specific value and are typically pegged to fiat currency like the US dollar. For example, DAI is a stablecoin pegged to USD and backed by ether (ETH).

Monerium is an Electronic Money Institute, or EMI. Monerium tokens are electronic money, or e-money. Like stablecoins, it's 1:1 to the Euro, Sterling pound and Dollar. The difference is that e-money is regulated and has been recognized in the European Economic Area and the UK as a digital alternative to cash since 2000 and is 1:1 backed in fully segregated, unencumbered, high-quality liquid assets.

To make a long story short, stablecoins act like money while e-money is money.

Wallets, test networks and gas

You'll need a blockchain wallet before we start. Essentially, it is a piece of software that allows you to store your money and other assets, easily conduct transactions and check your balance whenever you need to. We recommend using MetaMask for the Ethereum blockchain.

Networks are different Ethereum environments you can access for development, testing, or production use cases. Your wallet will work across the different networks but your account balance and transaction history won't carry over from the main Ethereum network. For taking your first steps and testing purposes, it's useful to know which networks are available and how to get testnet ETH so you can play around with it.

Monerium has created a sandbox environment that is connected to the rinkeby Ethereum test network. This allows you to play around with our money in a safe environment to understand how this fits into your application.

Sending money or other Ethereum based tokens requires the sender to include something called “Gas”. Gas, in Ethereum, is the metric used to calculate how much ETH you’ll pay the miners to mine your transaction or program (smart contract). The wallet will take care of calculating and paying the gas, but you will need to make sure that there is enough ETH in order to complete the transaction. However, you do not need to keep an ETH balance in order to receive or to store money in your wallet. You can get test ETH for rinkeby from the official faucet

OK, That was a lot! but don't worry! This sounds much more complicated than it actually is. Your wallet will do most of the work and we'll be using the same internet you know and love.

Let's get started! :)

Getting started

Before we start, here is a short demo video to showcase how we create an account and use a decentralised exchange platform like Uniswap to exchange EUR for GBP without any intermediaries and only using smart contracts.

Create a sandbox account

For the innovators, product builders, and other curious minds we've opened up a Sandbox version of our system. Play around with our money in a safe environment to understand how this fits into your platform.

Make sure you have Metamask or a compatible blockchain wallet ready and the rinkeby test network before we start.

  1. Start by signing up.
  2. Connect your wallet in the top right corner of the application.
  3. You should be taken to a Link your address page. Press the Link button. When you link your address, you are essentially proving that you are the real owner of the address. This is ensured by having you sign a message with the private key in your wallet.

You have now created your account and you should be able to switch between different currencies.

Adding tokens to your wallet

Now we want to add the EUR and GBP tokens in your wallet. to be able to send and receive the money directly in the wallet

Note! on the mainnet you simply search for Monerium tokens in the wallet and they appear. But now we add them manually because we are using the rinkeby testnet

  1. Select your EUR account.
  2. Press the More (three dots) button and account details should be visible.
  3. If you have a Metamask wallet you should see a Add EUR token to wallet button. Press the button and your wallet should ask you if you want to add the token. For other tokens you can enter the token address manually.
  4. Select your GBP account and add it the same way as you did for EUR.

You should now see both the EURe and GBPe tokens in your wallet with zero balance.

Let's fix that and add some test money from a test bank account to your blockchain address

Monerium IBAN

Customers can create a unique Monerium IBAN in their name that is connected to the SEPA payment network. This allows customers to seamlessly collect and send money between bank accounts and their blockchain address.

Let's create a Monerium IBAN for your EUR account.

  1. Select your EUR account in the sandbox.
  2. Press the green Add money button.
  3. Press the Continue button in the Get a Monerium IBAN panel.

You should now see your very own test Monerium IBAN.

PAY-IN / Collect money from bank account to blockchain

We are now going to simulate sending test euros from a test bank account to your blockchain address.

  1. Select your EUR account in the sandbox.
  2. Press the green Add money button.
  3. Enter €1,000 in in the Simulate a bank transfer panel and press the Add money button.

In about 15 seconds you should see the balance increase by €1,000 in the sandbox application and in your wallet.

PAY-OUT / Send money from blockchain to bank account

We are now going to simulate sending test euros from your blockchain address to a test bank account.

  1. Select your EUR account in the sandbox.
  2. Press the blue Send money button.
  3. Enter €500 in in the amount field.
  4. Enter GR16 0110 1250 0000 0001 2300 695 in the IBAN field, or any other valid IBAN you can think of.
  5. Enter any Company name e.g. Monerium and press the Send button.

In about 15 seconds you should see the balance decrease by €500 in the sandbox application and in your wallet.

E-money tokens

Ethereum

Monerium e-money tokens are live on Ethereum mainnet and testnets and are ERC20 and ERC677 compliant.


  contract Euro {

    // Transfers tokens [ERC20].
    transfer(to, amount)

    // Transfers tokens from a specific address [ERC20].
    transferFrom(from, to, amount)

    // Approves a spender [ERC20].
    approve(spender, amount)

    // Transfers tokens and subsequently calls a method
    // on the recipient [ERC677].
    transferAndCall(to, amount, data)

    // Returns the total supply.
    totalSupply()

    // Returns the number tokens associated with an address.
    balanceOf(who)

    // Returns the allowance for a spender.
    allowance(owner, spender)
  }

ERC20 / Approve and transfer from

The user gives your smart contract the right to take the money by itself from their address using the approve method. Once approved, your contract can call the transferFrom method in the Monerium contract and transfer money from the address.

ERC677 / Transfer and call

transferAndCall transfers money and calls the receiving contract's onTokenTransfer method with additional data and triggers an event Transfer.

The source code and more info about the token design can be found at our githup repo.

EURe / Euro on Ethereum

GBPe / Sterling on Ethereum

USDe / US Dollar on Ethereum

ISKe / Icelandic krona on Ethereum

Ethereum test money and develoment

Our sandbox is connected to the Rinkeby test network . Please fill out the developer information to get test money for the Ropsten or Kovan test networks.

Inforamtion on how to setup a local test environment can be found in our githup repo.

Algorand

Algorand comprehensive smart contract capabilities enable the creation of DeFi solutions and dApps that can scale to billions of users, tens of millions of daily transactions, with negligible transaction fees. Developers can find all the resources they need to turn their ideas into full-scale applications on the Algorand Developer Portal.

EURe / Euro on Algorand

Algorand test money and development

We have written a guide on how to get test euros on the Algorand testnet using the AlgoExplorer testnet dispenser and MyAlgo wallet.

Using the API

Environments

Monerium maintains several execution environments which may differ in features and availability guarantees. Each API environment comes with a web client which can be used during integration to visualize the data provided by the API.

Production

Environment which targets a production blockchain involving real emoney

Base URL api.monerium.app
Web client monerium.app
Availability Stable environment, publicly available
Features May be lagging behind other environments

Sandbox

Environment which targets a test blockchain involving fake emoney

Base URL api.monerium.dev
Web client sandbox.monerium.dev
Availability Stable environment, publicly available
Features Parity with production environment while simulating periphery services

Identifiers and time formats

Identifiers are used to identify resources and actors. All identifiers used by the API are Universally Unique Identifiers (UUID) on the form 123e4567-e89b-12d3-a456-426614174000. The UUID 00000000-0000-0000-0000-000000000000 is a special identifier reserved for the Monerium System. This essentially means that an automation was performed by the system. Dates are formatted according to RFC 3339, with sub-second precision, unless otherwise specified. Example date: 2021-02-13T16:41:10.095081Z. The Z at the end is a suffix which denotes a UTC offset of 00:00; often spoken “Zulu”.

Authentication

API consumers can authenticate themselves either by providing a valid HTTP cookie or by providing the username and password credentials according to the Basic HTTP Authentication Scheme. Using the web client a partner can sign up for an account using an email address, choose a password and verify the email address by clicking a link in an email which is sent upon registration. The partner can also reset the password using the web client. Both API authentication methods rely on the email and password credentials.

Note that in the examples below some HTTP headers have been removed for brevity.

Basic Authentication

In a Basic Authentication the credentials are included in the Authorization header. This is done by concatenating the credential pair using a colon and base64 encoding the result, base64(<email>:<password>).

The header thus becomes:

Authorization: Basic <base64 encoded credentials> 

Example:

$ curl -v -s --user '[email protected]:password' https://api.monerium.app/orders
> GET /orders HTTP/1.1
> Host: api.monerium.app
> Authorization: Basic dXNlckBleGFtcGxlLmNvbTpwYXNzd29yZA==
>
< HTTP/1.1 200 OK
< Content-Type: application/json; charset=utf-8

POST /login

The email and password must be POSTed to the login endpoint and encoded in a JSON object: {"username": "[email protected]", "password": "password"}

Example using cookies:

$ curl -v -s -d '{"username": "[email protected]", "password": "password"}' https://api.monerium.app/login
> POST /login HTTP/1.1
> Host: api.monerium.app
> Content-Type: application/x-www-form-urlencoded
>
< HTTP/1.1 200 OK
< Set-Cookie: session-id=MTYx...T5Kj; Path=/; Expires=Sat, 13 Feb 2021 17:35:49 GMT; Max-Age=108000; HttpOnly; Secure

Subsequent calls to the API provide the session-id as a cookie:

$ curl -v -s -H 'Cookie: session-id=MTYx...T5Kj' https://api.monerium.app/orders
> GET /orders HTTP/1.1
> Host: api.monerium.app
> Cookie: session-id=MTYx...T5Kj
>
< HTTP/1.1 200 OK
< Content-Type: application/json; charset=utf-8

The login context

GET /login

The login provides information about the authenticated user and the profile. This information is returned when a user POSTs valid credentials but may also be retrieved by doing a normal GET request.

$ curl -v -s --user '[email protected]:password' <BASEURL>/login
> GET /login HTTP/1.1
> Host: api.monerium.app
> Authorization: Basic dXNlckBleGFtcGxlLmNvbTpwYXNzd29yZA==
{
  "userId": "4f079f02-6d26-11eb-9bc8-acde48001122",
  "email": "[email protected]",
  "name": "[email protected]",
  "roles": [],
  "auth": {
    "method": "password",
    "subject": "[email protected]",
    "verified": true
  },
  "defaultProfile": "4f079ef8-6d26-11eb-9bc8-acde48001122",
  "profiles": [
    {
      "id": "4f079ef8-6d26-11eb-9bc8-acde48001122",
      "type": "corporate",
      "name": "[email protected]"
    }
  ]
}

Authenticated users may be authorized to access one or more profiles, which can either be personal or corporate profiles. The profile ID is the main identifier used to identify other API resources. The default profile allows the API consumer to use the simpler API endpoints omitting the profile ID from the URL structure.

Authorization

an either be public or protected. Users are authorized access based on a role they have been assigned or based on the concept of resource owners where a resource is owned by a profile and its associated users are granted access. Users are associated with a profile either because the user is the profile (personal profile) or the user is a member of the profile (corporate profile).

Linking addresses

Addresses are linked by providing Monerium with a digital signature using the associated private key. This signature proves the ownership of the address which allows Monerium to redeem emoney from the address, either as a part of a payout transaction or in case of a lost private key where the emoney is re-issued to a new address. The easiest way to link an address is to visit the web client using a web3 enabled wallet (MetaMask, WalletConnect, etc.) and it will guide you through the process.

Depending on your account management strategy a single address can be used to store emoney or multiple addresses. There is no limit on the number of linked addresses but because the signature for an outgoing payment is required, the associated private key must be available for all addresses.

Note that funds stored on addresses not linked to Monerium do not enjoy the consumer protection of lost private keys.

Balances

POST /balances POST /profiles/<profileId>/balances

Token balances for all linked addresses.

[
  {
    "id": "03444bba-76c0-11eb-9178-0e06a5e4ccf7",
    "chain": "ethereum",
    "network": "rinkeby",
    "address": "0x61d1Df91F98282e5AdC8224943E0336Ec8612d66",
    "balances": [
      {
        "currency": "eur",
        "amount": "90"
      },
      {
        "currency": "usd",
        "amount": "0"
      }
    ]
  }
]

Orders

Orders manage the lifecycle of the emoney. As such an order is created when new emoney is issued and when it is redeemed, and they contain information about the currency, amount, and the blockchain address. In addition information about the payer (for issue orders) beneficiary (for redeem order) is available as the counterpart.

Placing an order

POST /orders POST /profiles/<profileId>/orders

A payment to an external SEPA account is initiated by placing a redeem order. The payload includes the amount, currency and the beneficiary (counterpart). All SEPA payments must be authorized using a strong customer authentication. In short, users must provide two of three elements to authorize payments:

  • Knowledge: something only the user knows, e.g. a password or a PIN code
  • Possession: something only the user possesses, e.g. a mobile phone, and
  • Inherence: something the user is, e.g. the use of a fingerprint or voice recognition.

The authorization is implemented by requiring a signature derived from a private key (possession) in addition to a password (knowledge). A message, the signature and the address associated with the private key used to sign must be added to the request payload. The message must have the format:

Send <CURRENCY> <AMOUNT> to <IBAN> at <TIMESTAMP>

Note that the timestamp should be formatted as RFC822Z (RFC822 with numeric time zone) and that the timestamp should be accurate to the minute.

Example redeem payload:

{
  "type": "redeem",
  "amount": "1000",
  "currency": "EUR",
  "counterpart": {
    "identifier": {
      "standard": "iban",
      "iban": "GR1601101250000000012300695"
    },
    "details": {
      "companyName": "Company name",
      "firstName": "First name",
      "lastName": "Last name"
    }
  },

  "address": "0x61d1Df91F98282e5AdC8224943E0336Ec8612d66",
  "signature": "0x5b03...371c",
  "message": "Send EUR 1000 to GR16 0110 1250 0000 0001 2300 695 at Sat, 13 Feb 2021 15:48 +00:00"
}

For the counterpart identifier any valid IBAN is permitted. The IBAN may contain spaces, so both GR16 0110 1250 0000 0001 2300 695 and GR1601101250000000012300695 are valid.

For the counterpart details, either first name and last name are required for persons, or the company name for companies. The name should match the intended recipient and is passed along the SEPA transfer for banks to identify the payee. The address to redeem from can be any address linked to Monerium.

If the order is placed successfully the API returns the order object. See Retrieving a single order.

The address will be debited for the order amount and the bank account associated with the IBAN will be credited. In case the IBAN is provisioned by Monerium, e.g. an IBAN associated with another linked address in the same profile, the payment will result in emoney on that address.

Retrieving a single order

GET /orders/<orderId>

Example issue order:

{
  "id": "1af62814-6e07-11eb-9bc8-acde48001122",
  "profile": "4f079ef8-6d26-11eb-9bc8-acde48001122",
  "orderType": "issue",
  "address": "0x61d1Df91F98282e5AdC8224943E0336Ec8612d66",
  "amount": "5000",
  "currency": "eur",
  "counterpart": {
    "identifier": {
      "standard": "iban",
      "iban": "JO17 LYUU 2289 2691 5944 9413 1490 60"
    },
    "details": {
      "name": "Payer name",
      "firstName": "Payer first name",
      "lastName": "Payer last name",
    }
  },
  "memo": "This is the memo which is visible to both sender and receiver",
  "meta": {
    "placedBy": "00000000-0000-0000-0000-000000000000",
    "placedAt": "2021-02-13T14:23:56.124539Z",
    "approvedAt": "2021-02-13T14:23:58.116098Z"
  }
}

This order represents €5,000 which was minted to address 0x61d1Df91F98282e5AdC8224943E0336Ec8612d66 after a payment from the payer whose IBAN is JO17 LYUU 2289 2691 5944 9413 1490 60.

Example redeem order:

{
  "id": "00f7f16c-6e08-11eb-9bc8-acde48001122",
  "profile": "4f079ef8-6d26-11eb-9bc8-acde48001122",
  "orderType": "redeem",
  "address": "0x61d1Df91F98282e5AdC8224943E0336Ec8612d66",
  "amount": "1000",
  "currency": "eur",
  "counterpart": {
    "identifier": {
      "standard": "iban",
      "iban": "GR16 0110 1250 0000 0001 2300 695"
    },
    "details": {
      "name": "Beneficiary company name",
      "companyName": "Beneficiary company name"
    }
  },
  "meta": {
    "placedBy": "4f079f02-6d26-11eb-9bc8-acde48001122",
    "placedAt": "2021-02-13T14:30:22.035561Z",
    "approvedAt": "2021-02-13T14:44:34.767645Z"
  }
}

This order represents €1,000 which was burnt from address 0x61d1Df91F98282e5AdC8224943E0336Ec8612d66 and paid to the beneficiary whose IBAN is GR16 0110 1250 0000 0001 2300 695.

Retrieving all orders

GET /orders GET /profile/<profileId>/orders

The endpoint returns an array of order objects.

Payment notifications

GET /payments (websocket) GET /profile/<profileId>/payments (websocket)

API consumers can either poll the orders endpoint periodically or subscribe to a websocket for incoming payments notifications. The websocket adheres to the standard WebSocket Protocol and familiar websocket libraries can be used to subscribe to them. For testing purposes the wscat utility can come in handy.

$ npm install -g wscat
$ wscat --auth <email>:<password> -c wss://api.monerium.dev/payments

Example payment notification payload:

{
  "id": "46b6e61a-6e1a-11eb-9bc8-acde48001122",
  "profile": "4f079ef8-6d26-11eb-9bc8-acde48001122",
  "orderId": "1af62814-6e07-11eb-9bc8-acde48001122",
  "direction": "in",
  "currency": "eur",
  "amount": "5000",
  "counterpart": {
    "identifier": {
      "standard": "iban",
      "iban": "JO17 LYUU 2289 2691 5944 9413 1490 60"
    },
    "details": {
      "firstName": "Payer first name",
      "firstName": "Payer last name",
    }
  },
  "memo": "This is the memo which is visible to both sender and receiver",
  "meta": {
    "state": "processed",
    "processedBy": "00000000-0000-0000-0000-000000000000",
    "processedAt": "2021-02-13T16:41:10.095081Z"
  }
}

The payload includes the order ID which can be used to retrieve the order object which contains extra information, such as the address used to mint the emoney.

Token information

GET /tokens

Information about the emoney tokens with tickers, symbols, decimals, and token address.

[
  {
    "currency": "eur",
    "ticker": "EUR",
    "symbol": "EURe",
    "chain": "ethereum",
    "network": "rinkeby",
    "address": "0x25c13fc529dc4afe4d488bd1f2ee5e1ec4918e0b",
    "decimals": 18
  },
  {
    "currency": "gbp",
    "ticker": "GBP",
    "symbol": "GBPe",
    "chain": "ethereum",
    "network": "rinkeby",
    "address": "0x01df10e345d0364d3a5b8422a66af6305803bd1e",
    "decimals": 18
  },
  {
    "currency": "isk",
    "ticker": "ISK",
    "symbol": "ISKe",
    "chain": "ethereum",
    "network": "rinkeby",
    "address": "0x0c9d7a0d8bf4bc9d15f577bbf650ebc8044a71db",
    "decimals": 18
  },
  {
    "currency": "usd",
    "ticker": "USD",
    "symbol": "USDe",
    "chain": "ethereum",
    "network": "rinkeby",
    "address": "0x09c0a236e1227500f495cb0731c4af69b49639a5",
    "decimals": 18
  }
]

Errors

Errors returned by the API honor HTTP error codes and they all share the same shape.

{
  "code": <http error code>,
  "status": <http error status>,
  "message": "<error message>",
  "errors": {
    "<field>": "<validation error>",
    "<field>": "<validation error>",
  },
  "details": {
    "<key>": "<value>",
  },
  "errorId": "<UUID>"
}

The code, status and message are always returned but errors and details augment the error message where relevant. The error ID is available for internal server errors and can be used by Monerium to identify the root error cause.

Bad request error

Bad request errors are probably the most common errors. They indicate that the request structure or the payload are incorrect. The API consumer should revisit the request values and try again.

< HTTP/1.1 400 Bad Request
< Content-Type: application/json; charset=utf-8
{
  "code": 400,
  "status": "Bad Request",
  "message": "Incorrect username or password"
}

A special type of a bad request error is the validation error. This indicates that the structure and the payload is correct but a business rule has been violated.

< HTTP/1.1 400 Bad Request
< Content-Type: application/json; charset=utf-8
{
  "code": 400,
  "status": "Bad Request",
  "message": "Validation errors",
  "errors": {
    "password": "This field is required",
    "username": "This field is required"
  }
}

Authorization error

This error is returned when the user has been correctly authenticated but lacks permission to access a resource.

< HTTP/1.1 403 Forbidden
< Content-Type: application/json; charset=utf-8
{
  "code": 403,
  "status": "Forbidden",
  "message": "User [email protected] is forbidden"
}

Not found error

Two types of not found errors may be returned. If the requested URL does not exist a plain text error is returned.

< HTTP/1.1 404 Not Found
< Content-Type: text/plain; charset=utf-8
<
404 page not found

If the requested URL exists but the resource does not exist a more detailed JSON error is returned.

< HTTP/1.1 404 Not Found
< Content-Type: application/json; charset=utf-8
{
  "code": 404,
  "status": "Not Found",
  "message": "Order not found: 9158065a-6a8b-11eb-9376-a683e7c51eb8",
  "details": {
    "id": "9158065a-6a8b-11eb-9376-a683e7c51eb8",
    "resource": "order"
  }
}

Internal server error

In exceptional circumstances an internal server error may be returned. This indicates that the problem lies with Monerium. This may be a temporary error or a permanent error. Included in the error object is an error ID which can be used by Monerium to identify the root error cause.

< HTTP/1.1 500 Internal Server Error
< Content-Type: application/json; charset=utf-8
{
  "code": 500,
  "status": "Internal Server Error",
  "message": "Unknown error",
  "errorId": "7326c964-6e23-11eb-98d8-acde48001122"
}