Using the API v1.3-beta

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 the username and password credentials according to the Basic HTTP Authentication Scheme or by providing an OAuth 2.0 access token according to the The OAuth 2.0 Authorization Framework: Bearer Token Usage. 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

Bearer authentication NEW

In a Bearer Authentication the credentials are included in the Authorization header. The access token, which is used as a bearer token, can be acquired using either of the following OAuth 2.0 flows:

Example accessing REST resources using the access token:

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

Example accessing WebSocket resources using the access token:

Browsers do not permit setting an HTTP header when opening a WebSocket and therefore most WebSocket libraries, especially those written in JavaScript, do not support adding the access token as a bearer token in the authorization header. For that reason, the access token can be passed in the query parameters when connecting to WebSocket resources.

wss://api.monerium.dev/orders?access_token=MTQ0NjJkZmQ5OTM2NDE1ZTZjNGZmZjI3

The authentication context

GET /auth/context

The authentication context provides information about the authenticated user and the profile. This information is returned when an authenticated user performs a normal GET request.

$ curl -v -s --user '[email protected]:password' <BASEURL>/auth/context
> GET /auth/context 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]",
      "perms": [
        "read",
        "write"
      ]
    }
  ]
}

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 represent ownership of 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

Authorization code flow with proof key for code exchange (PKCE) NEW

When public clients, e.g. native or single-page applications, request access tokens, some additional security concerns are posed that are not mitigated by the authorization code flow alone. This is because:

Native apps
  • Cannot securely store a client secret. Decompiling the app will reveal the client secret, which is bound to the app and is the same for all users and devices.
  • May make use of a custom URL scheme to capture redirects, e.g. MyApp://, potentially allowing malicious applications to receive an authorization code from your authorization server.
Single page apps
  • Cannot securely store a client secret because their entire source is available to the browser.

Given this, OAuth 2.0 provides a version of the authorization code flow which makes use of a proof key for code exchange (PKCE) (defined in OAuth 2.0 RFC 7636). The PKCE-enhanced authorization code flow introduces a secret created by the calling application that can be verified by the authorization server; this secret is called the code verifier. Additionally, the calling app creates a code challenge, by hashing the code verifier, and sends this value over HTTPS to retrieve an authorization code. This way, a malicious attacker can only intercept the authorization code but they cannot exchange it for a token without the code verifier.

At a high level, the entire authorization flow for a partner application looks a like this:

1. Generating the code challenge for PKCE in OAuth 2.0
When the user initiates an authentication flow, the client should compute a code_verifier. This must be a random, high entropy string between 43 and 128 characters. Next up, the client computes a code_challenge starting from the code_verifier (see also rfc7636, section 4). This is the result of the following pseudo-code:

code_challenge = base64urlEncode(SHA256(ASCII(code_verifier)))

The code_challenge must be sent in the first step of the authorization flow. The code_verifier instead must be included along the initialrequest to the authorization server for requesting the Access Token.

2. Authorization code request query parameters
The authorization flow begins with the appliction directing the user to the Monerium API by either POST or GET request to the /auth endpoint with the following required oauth parameters:

POST /auth GET /auth

Parameter Modifier Description
client_id Required Each client for an application is registered separately by the Monerium team and each one is given a unique client_id.
code_challenge Required The code challenge is either the code verifier (if code_challenge_method=plain or missing) or the SHA256 of the code verifier if code_challenge_method=S256. Required when the client is public (i.e. no client_secret is presented to the token endpoint).
code_challenge_method Optional Either plain (default) or S256.
response_type Default: code Only supports authorization code flow.
redirect_uri Optional The redirect URL of your app, where authentication responses can be sent and received by your app. If present, must match one of the registered redirect URLs exactly. Not required if only one redirect URL is registered. Only URLs with the HTTPS-scheme are supported with the exception of http://localhost.
scope Default: orders:read What capabilities to request.
state Recommended The state parameter is used by the application to store request-specific data and/or prevent CSRF attacks.
address Optional Require the user to set up a Monerium IBAN for a specific blockchain address.

3-4. Authorization and onboarding
During the authorization flow, the users are automatically directed to a Monerium authorization screen that can be styled to fit the application. The user either authenticates with their username or passwords or signs up. After they have successfully onboarded, they grant your applcation access according to the requested scope.

5. Authorization response
Once the authorization is granted, users will be redirected to the redirect URL with the authorization code as a query parameter. If you include a state parameter in the initial authorization URL, it will be included in the redirect URL after the user authorizes your app. Your app should compare the state with the state it created in the initial request. This helps ensure that you only exchange authorization codes that you requested, preventing attackers from redirecting to your callback URL with arbitrary or stolen authorization codes.

Parameter Description
code The authorization code indicates that the app got the permissions as requested and it can be exchanged for access tokens by calling the token endpoint.
state The response includes the exact value from the state parameter in the initial request, which may be the empty string. The landing page should verify that the state parameters are identical.

Example authorization code successful response:

HTTP/2 301
Location: https://app.com/landingpage
?code=123456789d&state=session-123

Error responses may also be sent to the redirect URL so the application can handle them appropriately:

Error Parameter Description
error An error code string that can be used to classify types of errors that occur, and can be used to react to errors.
error_description A specific error message that can help a developer identify the root cause of an authentication error.
error_uri A link to more detailed information about the error and how to resolve it.

The following table describes the various error codes that can be returned in the error parameter of the error response.

Error code Description
access_denied Resource owner denied consent.
invalid_request The request is missing a required parameter, includes an invalid parameter value, or is otherwise malformed.
unauthorized_client The client is not authorized to request an authorization code using this method.
unsupported_response_type The authorization server does not support obtaining an authorization code using this method.
invalid_scope The requested scope is invalid, unknown, or malformed.
server_error The authorization server encountered an unexpected condition which prevented it from fulfilling the request.
temporarily_unavailable The authorization server is currently unable to handle the request due to a temporary overloading or maintenance of the server.

6. Redeem code for access token
Now that the application has acquired an authorization_code and has been granted permission by the user, the code can be redeemed for an access_token using grant_type=authorization_code. Do this by sending a POST request to the token endpoint with the following query parameters.

POST /auth/token GET /auth/token

Parameter Modifier Description
client_id Required The client ID that Monerium assigned to your app.
code Required The authorization code that you acquired in the first leg of the flow.
redirect_uri Required The same redirect_uri value that was used to acquire the authorization code.
grant_type Required Must be authorization code for the authorization code flow.
code_verifier Required The same code_verifier that was used to obtain the authorization code. Required if PKCE was used in the authorization code grant request.
scope Optional What capabilities to request.

Example request

curl --silent --show-err --data code=xxx -d grant_type=authorization_code
  -d client_id=1234 -d code_verifier=abc  -d redirect_uri=http://app.com/landing
  https://api.monerium.dev/auth/token

7-8. Access token
The Monerium API verifies the authorization code, code_challenge and code_verifier. The Monerium API responds with the following values.

Value Description
access_token The access token string as issued by the authorization server.
token_type The type of token this is, typically just the string “bearer”.
expires_in If the access token expires, the server includes with the number of seconds the access token is valid for.
refresh_token If the access token expires, the server includes a refresh token which applications can use to obtain another access token.
profile Customers are represented in the API by profiles whose identifier is the profile ID. All resources, such as orders, are owned by a profile. This ID can also be used to get profile identity information and onboarding status.
userId Unique ID for the user that granted the authorization. Users can be associated with profiles which grants them access to the resources owned by the profile. Usually there is a 1-to-1 relationship between a user and a personal profile but often there is a many-to-one relationship or many-to-many relationship between users and corporate profiles.

Example response

{
  "access_token":"MTQ0NjJkZmQ5OTM2NDE1ZTZjNGZmZjI3",
  "token_type":"Bearer",
  "expires_in":3600,
  "refresh_token":"IwOGYzYTlmM2YxOTQ5MGE3YmNmMDFkNTVk",
  "scope":"orders:read"
  "profile":"asd1234f-f05e-11eb-8143-62d421e33aed",
  "userId":"qwer6789-f05e-11eb-8143-62d421e33aed"
}

9-10. Refreshing the access token
Access tokens are short lived and you must refresh them after they expire to continue accessing resources. You can do so by submitting another POST or GET request to the /auth/token endpoint, this time providing the refresh_token instead of the code.

POST /auth/token GET /auth/token

Parameter Modifier Description
client_id Required The client ID that Monerium assigned to your app.
refresh_token Required The refresh_token that was captured with the last access_token.
grant_type Required The grant_type parameter must be set to refresh_token.
scope Optional What capabilities to request.

Example refresh request

curl --silent --show-err --data refresh_token=xxx -d grant_type=refresh_token -d client_id=1234 https://api.monerium.dev/auth/token

  POST /auth/token HTTP/1.1
  Host: api.monerium.dev

  refresh_token=xxx
  &grant_type=refresh_token
  &client_id=1234

Example refresh response

{
  "access_token":"MTQ0NjJkZmQ5OTM2NDE1ZTZjNGZmZjI3",
  "token_type":"Bearer",
  "expires_in":3600,
  "refresh_token":"IwOGYzYTlmM2YxOTQ5MGE3YmNmMDFkNTVk",
  "scope":"orders:read"
  "profile":"asd1234f-f05e-11eb-8143-62d421e33aed",
  "userId":"qwer6789-f05e-11eb-8143-62d421e33aed"
}

Client credentials authorization flow NEW

POST /auth/token GET /auth/token

Confidential clients which can hide their credentials, e.g. backend servers, can be enlisted in Monerium's partner program, which enables them simultaneous access to multiple profiles which have granted authorization. These clients can get an access_token using the following query parameters:

Parameter Modifier Description
client_id Required The client ID, Monerium assigned to your app.
client_secret Required A secret that was generated by Monerium.
grant_type Required Must be client_credientials.
scope Optional What capabilities to request.

Example request using client credentials:

curl --silent --show-err --data client_id=xxx
  -d client_secret=yyy -d grant_type=client_credientials
  -d https://api.monerium.dev/auth/token

Example refresh response

{
  "access_token": "VQ6RC-4MRAKqYsgjO14I4Q",
  "expires_in": 3600,
  "profile": "db72c97c-05f4-11ec-84a9-2e0d2d9b5fdb",
  "refresh_token": "y3WiyeRCRGKRNb5AmAhdBg",
  "token_type": "Bearer",
  "userId": "bce93e55-e966-11eb-afc2-2e0d2d9b5fdb"
}

Profiles NEW

Customers are represented by profiles whose identifier is the profile ID. The profile kind is used to differentiate between personal profiles and corporate profiles. All resources, such as orders, are owned by a profile. Users and external applications can be associated with profiles which grants them access to the resources owned by the profile. Usually there is a 1-to-1 relationship between a user and a personal profile but often there is a many-to-one relationship or many-to-many relationship between users and corporate profiles, where a single user may have access to multiple corporate profiles and multiple users may have access to a single corporate profile.

Partners configure an application which requests access to profiles and upon approval from a user, who is authorized to grant access to the profile, the application may perform actions on resources owned by the profile.

Retrieving a single profile

GET /profiles/<profile>

Example issue profile:

{
  "id": "1af62814-6e07-11eb-9bc8-acde48001122",
  "name": "ACME INC",
  "kyc": {
    "state": "absent | submitted | pending | confirmed"
    "outcome": "approved | rejected | unknown"
  },
  "accounts": [
     {
       address: "0x123",
       currency: "eur"
       standard: "iban"
       iban: "ES1234490001550007045744"
     },
     {
       address: "0x123",
       currency: "gbp"
       standard: "scan"
       sortCode: "123456",
       accountNumber: "12345678",
     },
     {
       address: "0xAd284e5b133F0DD3fE1bb0e1953b2eaB2035977C",
       currency: "eur"
     },
}
Property Type Description
id string The profile ID.
name string Profile name, this can be a corporate or an individual.
kyc.state string The state of the customer onboarding (KYC = Know Your Customer). The state can be:
absent: there is no KYC version available.
submitted: the user has submitted KYC data but it has not been processed
pending: the admin has started processing the KYC application
confirmed: an admin has decided on the outcome of a KYC application
kyc.outcome string Outcome is a verdict for a profile from Monerium. The outcome can be:
approved: valid customer
rejected: applicant was rejected because the did not meet the KYC requirements
unknown: Outcome has not been reached
accounts[].address string Ethereum blockchain address of the account
accounts[].currency string The account currency. Can be eur, gbp, usd or isk.
accounts[].standard string Payment system standard for the bank payments. Can be iban (International Bank Account Number) or scan (used in the British banking industry to route money transfers between banks domestically).
accounts[].iban string International Bank Account Number. Only present if standard is iban
accounts[].sortCode string The sort code is used by the British banking industry to route money transfers between banks domestically. The code identifies both the bank and the branch where the account is held. Only present if standard is scan
accounts[].accountNumber string Bank account number at the bank and the branch specified in the sort code. Only present if standard is scan

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:

{
  "kind": "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 GR1601101250000000012300 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",
  "kind": "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": {
    "state": "processed",
    "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",
  "kind": "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"
    }
  },
  "rejectedReason": "IBAN does not match beneficiary name",
  "meta": {
    "state": "rejected",
    "placedBy": "4f079f02-6d26-11eb-9bc8-acde48001122",
    "placedAt": "2021-02-13T14:30:22.035561Z",
    "rejectedAt": "2021-02-13T14:44:34.767645Z"
  }
}

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

Order states

Orders can be in one of the following states:

State Description
placed The order has been created, but payment has not been received.
pending The order is being processed by Monerium.
processed The order has been processed successfully (approved).
rejected The order could not be processed by Monerium. The rejected reason is documented in the order rejectedReason field.

Retrieving all orders NEW

GET /orders

The endpoint returns an array of order objects which the authenticated user has access to. The following query parameters can be used to filter and sort the results:

Parameter Description
address Get all orders that belong to a specific ethereum blockchain address
Example: 0x87B99DAc6191B8118eC2f16218B66b63ef828AA2
txHash The order could not be processed by Monerium. The rejected reason is documented in the order rejectedReason field.
Example: 0x692ff12125b71c167b3ea90bddb3b28edd60941851cb0cdd852cc3b6d79311cd
memo Filter on memo field a.k.a. payment reference.
profile Get all orders that belong to a specific profile UUID.
Example: 123e4567-e89b-12d3-a456-426614174000
accountId Get all orders that belong to a specific emoney account UUID.
Example: 456e4567-e89b-12d3-a456-426614174000
state Get all orders in a particular state
Example: processed

Example:


$ curl -s -S -H 'Authorization: Bearer MTQ0NjJkZmQ5OTM2NDE1ZTZjNGZmZjI3' 'https://api.monerium.dev/orders'
> GET /orders HTTP/1.1
> Host: api.monerium.dev
> Authorization: Bearer MTQ0NjJkZmQ5OTM2NDE1ZTZjNGZmZjI3

< HTTP/1.1 200 OK
< Content-Type: application/json; charset=utf-8
  
[
  {
    "id": "1af62814-6e07-11eb-9bc8-acde48001122",
    "profile": "4f079ef8-6d26-11eb-9bc8-acde48001122",
    "kind": "issue",
    "address": "0x61d1Df91F98282e5AdC8224943E0336Ec8612d66",
    "amount": "5000",
    "currency": "eur",
    ...
  },

  ...

  {
    "id": "00f7f16c-6e08-11eb-9bc8-acde48001122",
    "profile": "4f079ef8-6d26-11eb-9bc8-acde48001122",
    "kind": "redeem",
    "address": "0x61d1Df91F98282e5AdC8224943E0336Ec8612d66",
    "amount": "1000",
    "currency": "eur",
    ...
    "meta": {
      "cursor": "q6kC-AYKEeyHnS4NLZtf2w",
      ...
    }
  }
]

Order notifications NEW

GET /orders (websocket)

API consumers can either poll the orders endpoint periodically or subscribe to a websocket for order 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/orders

The websocket server will periodically send a PING control frame, to which the websocket consumer must respond with a PONG control frame. In the case the PONG is not sent in a timely manner the websocket server will close the connection to preserve resources. Many libraries handle this logic for the developer.

The shape of the orders received over the websocket is the same as the orders received from the API directly. Please see Retrieving a single order for reference.

The websocket will emit the same order three times, once for the following state changes:

  1. placed - the initial state
  2. pending - money has been received for issue orders or tokens have been burnt for redeem orders.
  3. processed - the final state

The following query parameters can by used to filter the orders:

Parameter Description
state Emits all orders in a specific state.
Example: processed
profile Emits all orders that belong to a specific profile UUID.
Example: 123e4567-e89b-12d3-a456-426614174000

Example:

$ wscat -c wss://api.monerium.dev/orders?access_token=MTQ0NjJkZmQ5OTM2NDE1ZTZjNGZmZjI3&state=processed

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. The endpoint may not exist.

< HTTP/1.1 404 Not Found
< Content-Type: application/json; charset=utf-8
<
{
  "code": 404,
  "status": "Not Found",
  "message": "Endpoint not found: /does-not-exist",
  "details": {
    "id": "/does-not-exist",
    "resource": "endpoint"
  }
}

If the endpoint exists but the resource does not the following 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"
}