NAV Navbar
shell ruby python javascript

Introduction

Welcome to the Appia API. You can use our API to access Appia endpoints, which can query balances and transactions and tell you which of our users are cat people (jk, we deliberately don't know anything about our users).

We have language bindings in Shell, Ruby, Python, and JavaScript. BOOM. You can view code examples in the dark area to the right, and you can switch the programming language of the examples with the tabs in the top right.

Oh by the way, Simon Dingle has an extremely silly face. 😜

To be discussed:

Authentication

Update 15 Jan 2019: not yet implemented

To authorise, use this code:

require 'appia'

api = Appia::APIClient.authorize!('mypersonalapikey')
import appia

api = appia.authorize('mypersonalapikey')
# With shell, you can just pass the correct header with each request
curl "api_endpoint_here"
  -H "Authorization: mypersonalapikey"
const appia = require("appia");

let api = appia.authorize("mypersonalapikey");

Make sure to replace mypersonalapikey with your API key.

Appia uses API keys to allow access to the API. To register a new API key, buy Kenny a beer and hope that he takes pity on you.

Appia expects for the API key to be included in all API requests to the server in a header that looks like the following:

Authorization: mypersonalapikey

Prices

Update 15 Jan 2019: implemented but not saved to a database

Price data of a set of assets / symbols (from_symbols) in a chose currency / symbol (to_symbol), gathered through our price aggregation.

Currently it calls the source(s) in real-time, but soon we will start caching the answers and do scheduled refreshes

curl "http://api.lettuce.money/prices?to_symbol=ZAR&from_symbols=BTC,USD,MSFT"
  -H "Authorization: mypersonalapikey"

The above command returns JSON structured like this:

{
  "timestamp": "2019-01-01T00:00:01.001Z",
  "toSymbol": "ZAR",
  "fromSymbols": [
    {
      "fromSymbol": "BTC",
      "lastUpdated": "2018-12-31T11:59:01.001Z",
      "price": 0.000021,
      "source": "Crypto Compare"
    },
    {
      "fromSymbol": "USD",
      "lastUpdated": "2018-12-31T11:58:01.001Z",
      "price": 0.07,
      "source": "Crypto Compare"
    },
    {
      "fromSymbol": "MSFT",
      "last_updated": "2018-12-31T11:57:01.001Z",
      "price": 1535.01,
      "source": "Alpha Vantage"
    }
  ]
}

Users

Update 15 Jan 2019: implemented only in the front-ends

We do not store any personal information about our users.

Every user is given a unique ID when the account is created.

In the future, users will be able to belong to groups. This is not available in our MVP, though, so set all "groups" to "null".

Get All Users

require 'appia'

api = Appia::APIClient.authorize!('mypersonalapikey')
api.users.get
import appia

api = appia.authorize('mypersonalapikey')
api.users.get()
curl "http://example.com/api/users"
  -H "Authorization: mypersonalapikey"
const appia = require("appia");

let api = appia.authorize("mypersonalapikey");
let users = api.users.get();

The above command returns JSON structured like this:

[
  {
    "id": 12345678,
    "groups": null,
    "deleted": false,
    "baseCurrency": "ZAR",
    "baseCurrencySymbol": "R",
    "lastActivity": "2012-04-23T18:25:43.511Z",
    "latestBalance": {
      "amount": 203232.39,
      "debitOrCredit": "debit",
      "currency": "ZAR",
      "time": "2012-04-23T18:25:43.511Z"
    }
  },
  {
    "id": 22345679,
    "groups": null,
    "deleted": false,
    "baseCurrency": "BTC",
    "baseCurrencySymbol": "Ƀ",
    "lastActivity": "2017-04-23T18:25:43.511Z",
    "latestBalance": {
      "amount": 2.39,
      "debitOrCredit": "debit",
      "currency": "BTC",
      "time": "2012-04-23T18:25:43.511Z"
    }
  }
]

This endpoint retrieves all users.

HTTP Request

GET http://inves.technology/api/users

Query Parameters

Parameter Default Description
include_deleted false If set to true, the result will also include deleted users.

Get a Specific User

require 'appia'

api = Appia::APIClient.authorize!('mypersonalapikey')
api.users.get(12345678)
import appia

api = appia.authorize('mypersonalapikey')
api.users.get(12345678)
curl "http://inves.technology/users/212345678"
  -H "Authorization: mypersonalapikey"
const appia = require("appia");

let api = appia.authorize("mypersonalapikey");
let max = api.users.get(12345678);

The above command returns JSON structured like this:

{
  "id": 12345678,
  "groups": null,
  "deleted": false,
  "baseCurrency": "ZAR",
  "baseCurrencySymbol": "R",
  "lastActivity": "2012-04-23T18:25:43.511Z",
  "latestBalance": {
    "amount": 203232.39,
    "debitOrCredit": "debit",
    "currency": "ZAR",
    "time": "2012-04-23T18:25:43.511Z"
  }
}

This endpoint retrieves a specific user.

HTTP Request

GET http://inves.technology/users/<ID>

URL Parameters

Parameter Description
ID The ID of the user to retrieve

Delete a Specific User

require 'appia'

api = Appia::APIClient.authorize!('mypersonalapikey')
api.users.delete(12345678)
import appia

api = appia.authorize('mypersonalapikey')
api.users.delete(12345678)
curl "http://inves.technology/api/users/12345678"
  -X DELETE
  -H "Authorization: mypersonalapikey"
const appia = require("appia");

let api = appia.authorize("mypersonalapikey");
let max = api.users.delete(12345678);

The above command returns JSON structured like this:

{
  "id": 12345678,
  "deleted": true
}

This endpoint deletes a specific user.

HTTP Request

DELETE http://inves.technology/users/<ID>

URL Parameters

Parameter Description
ID The ID of the user to delete

Portfolios

Update 15 Jan 2019: not yet implemented

A user can have multiple portfolios. A portfolio is a collection of accounts. By defualt, every user has 1 portfolio called "My Moneh".

Users can add up to 3 portfolios on the free tier, and can add up to 100 portfolios on the paid tier (TBC).

NOTE:

Get All Portfolios

require 'appia'

api = Appia::APIClient.authorize!('mypersonalapikey')
api.portfolios.get
import appia

api = appia.authorize('mypersonalapikey')
api.portfolios.get()
curl "http://example.com/api/portfolios"
  -H "Authorization: mypersonalapikey"
const appia = require("appia");

let api = appia.authorize("mypersonalapikey");
let portfolios = api.portfolios.get();

The above command returns JSON structured like this:

[
  {
    "id": 12345678,
    "name": "My Moneh",
    "user": 12345678,
    "accounts": [2392392, 2301938, 2938218],
    "latestBalance": {
      "amount": 2.39,
      "debitOrCredit": "debit",
      "currency": "BTC",
      "time": "2012-04-23T18:25:43.511Z"
    }
  },
  {
    "id": 12345679,
    "name": "Genesis Mining Income",
    "user": 12345678,
    "accounts": [2392393, 2301938],
    "latestBalance": {
      "amount": 1.39,
      "debitOrCredit": "debit",
      "currency": "ETH",
      "time": "2012-04-23T18:25:43.511Z"
    }
  }
]

This endpoint retrieves all portfolios.

Accounts

Update 15 Jan 2019: implemented on the front-ends only

An account has a balance. A balance is a record of the current state of the account. An account can only have one type of asset inside it. That asset could be a currency, cryptocurrency, units of a fund, value of a house, or many other things. You cannot have a single account that is made up of two different currencies - as far as our system is concerned, those are two different accounts. It might, however, be helpful to sometimes group similar accounts for our users.

An account is somewhere, usually at an institution (e.g. Luno, Barclays) but sometimes on a paper wallet or in the deeds office (if I own a house). For consistency, our data structure will refer to all of these "wheres" as institutions even if it's a leather wallet in the user's backpack.

All balances are made up of a quantity of an asset that has a current price in the user's base currency. The quantity is the result of the sum of transactions that occured on an account.

Sometimes we know a lot about an account, so we can derive the current balance ourselves. For instance, say I have an account with Luno, and I own 10 ETH and 2 Bitcoins on that platform. I like to see everything converted back to South African Rands (this is my base currency). The price of BTC at this moment is R 90,000 and the price of ETH is R 2 000. Appia sees this as me having two accounts:

  1. A Luno (institution) ETH (asset) account with a quantity of 10 at a current price in my base currency of R 2 000. The balance of my account is therefore R 20 000. The asset type is "cryptocurrency".
  2. A Luno (institution) BTC (asset) account with a quantity of 2 at a current price in my base currency of R 90 000. The balance of my account is therefore R 180 000. The asset type is "cryptocurrency".

Say I also have an international share portfolio through EasyEquities. I own 15 shares in the S&P 500 that are worth R 100 each, and 3 shares of Netflix that are worth R 50 each. IF I am able to scrape all of this data with Appia, then Appia will see this as 2 accounts:

  1. A EasyEquities (institution) S&P 500 (asset) account with a quantity of 15 at a current price in my base currency of R 100. The balance of my account is therefore R 1 500. The asset type is "international equities".
  2. A EasyEquities (institution) Netflix (asset) account with a quantity of 3 at a current price in my base currency of R 50. The balance of my account is therefore R 150. The asset type is "international equities".

However, I may not be able to get this level of detail back from EasyEquities. In that case, Appia might see this as one account that we don't know a lot about:

  1. A EasyEquities (institution) account with a balance of R 1 650. I might know that the asset type is "international equities" but I may not know exactly what assets are held in that account.

Sometimes the asset held in a user's account will be identical to their base currency. It is still important to track the quantity separately to the balance where possible, though, because the user can change their base currency at any time.

require 'appia'

api = Appia::APIClient.authorize!('mypersonalapikey')
api.accounts.get
import appia

api = appia.authorize('mypersonalapikey')
api.accounts.get()
curl "http://example.com/api/accounts"
  -H "Authorization: mypersonalapikey"
const appia = require("appia");

let api = appia.authorize("mypersonalapikey");
let accounts = api.accounts.get();

The above command returns JSON structured like this:

[
  {
    "id": 12345678,
    "where": "Ledger Nano",
    "type": "tracked", // Can be "tracked" or "manual", in future releases, could be "linked"
    "assetSymbol": "ETH",
    "assetName": "Ethereum",
    "assetType": "cryptocurrency",
    "portfolios": [
      // Optional: this account is listed in 2 portfolios
      129302,
      230199
    ],
    "latestBalance": {
      "debitOrCredit": "debit",
      "price": 10, // In that user's base_currency
      "quantity": 2.39,
      "value": 20.9,
      "currency": "ZAR",
      "time": "2012-04-23T18:25:43.511Z",
      "source": "Crypto Compare"
    }
  },
  {
    "id": 12345679,
    "where": null,
    "type": "tracked", // Can be "tracked" or "manual", in future releases, could be "linked"
    "assetSymbol": "VOD.JS",
    "assetName": "Vodacom South Africa",
    "assetType": "equity",
    "latestBalance": {
      "value": 20.9, // For some accounts, we only return a value
      "currency": "ZAR",
      "time": "2012-04-23T18:25:43.511Z",
      "source": "Alpha Vantage"
    }
  },
  {
    "id": 12345674,
    "where": "Botswana",
    "type": "manual", // Can be "tracked" or "manual", in future releases, could be "linked"
    "assetSymbol": "ZAR",
    "assetName": "4 cows",
    "assetType": "manual",
    "latestBalance": {
      "value": 2000,
      "currency": "ZAR",
      "time": "2012-04-23T18:25:43.511Z",
      "source": "manual"
    }
  }
]

Balances

Update 15 Jan 2019: not yet implemented

The historical and current balance of each user for each account, portfolio, and user overall. These balances are calculated at midnight for each user and stored historically. Today's balance is stored temporarily in this database if it's requested by a front-end, but it is over-written at midnight.

require 'appia'

api = Appia::APIClient.authorize!('mypersonalapikey')
api.balances.get
import appia

api = appia.authorize('mypersonalapikey')
api.balances.get()
curl "http://example.com/api/balances"
  -H "Authorization: mypersonalapikey"
const appia = require("appia");

let api = appia.authorize("mypersonalapikey");
let balances = api.balances.get();

The above command returns JSON structured like this:

[
  {
    "id": 12345678, // Can we rather use User-Date as the primary key?
    "user": 12345678,
    "day": "20180812",
    "baseCurrency": "GBP", // all values below are expressed in this baseCurrency
    "totalBalance": {
      "amount": 39293.29,
      "currency": "GBP"
    },
    "portfolioBalances": [
      {
        "portfolio": 230293,
        "value": 239.23
      },
      {
        "portfolio": 330293,
        "value": -2939.29
      }
    ],
    "accountBalances": [
      {
        "manual": false,
        "account": 230293,
        "asset": "BTC",
        "amount": 1.3,
        "value": 29293.23
      },
      {
        "manual": true,
        "account": 320323,
        "asset": null,
        "amount": null,
        "value": 3923.23
      }
    ]
  }
]

Events

Update 15 Jan 2019: not yet implemented

A log of all of the events that change the values of any account in the system. What occured, at what time, for what user. These events are things like: a transaction or trade was initiated, processed, rejected, failed or reversed. A new account was created or deleted.

require 'appia'

api = Appia::APIClient.authorize!('mypersonalapikey')
api.events.get
import appia

api = appia.authorize('mypersonalapikey')
api.events.get()
curl "http://example.com/api/events"
  -H "Authorization: mypersonalapikey"
const appia = require("appia");

let api = appia.authorize("mypersonalapikey");
let events = api.events.get();

The above command returns JSON structured like this:

[
  {
    "id": 12345678,
    "user": 12345678,
    "time": "2012-04-23T18:25:43.511Z",
    "event": "New account linked"
  }
  // More events //
]

Assets

Update 15 Jan 2019: not yet implemented

A dictionary of all available assets.

require 'appia'

api = Appia::APIClient.authorize!('mypersonalapikey')
api.assets.get
import appia

api = appia.authorize('mypersonalapikey')
api.assets.get()
curl "http://example.com/api/assets"
  -H "Authorization: mypersonalapikey"
const appia = require("appia");

let api = appia.authorize("mypersonalapikey");
let users = api.assets.get();

The above command returns JSON structured like this:

[
  {
    "symbol": "ETH",
    "name": "Ethereum",
    "assetType": "cryptocurrency",
    "displaySymbol": "Ξ",
    "region": "United States"
  }
  // More assets //
]

Asset Types

Update 15 Jan 2019: not yet implemented

A dictionary of all available asset types, and arrays of the asset symbols included in that type.

require 'appia'

api = Appia::APIClient.authorize!('mypersonalapikey')
api.assetTypes.get
import appia

api = appia.authorize('mypersonalapikey')
api.assetTypes.get()
curl "http://example.com/api/assetTypes"
  -H "Authorization: mypersonalapikey"
const appia = require("appia");

let api = appia.authorize("mypersonalapikey");
let assetTypes = api.assetTypes.get();

The above command returns JSON structured like this:

[
  {
    "assetType": "cryptocurrency",
    "assets": ["ETH", "BTC", "LTC"]
  }
  // More asset types //
]

Errors

Update 15 Jan 2019: not yet implemented

The Appia API uses the following error codes:

Error Code Meaning
400 Bad Request -- Your request is invalid.
401 Unauthorized -- Your API key is wrong.
403 Forbidden -- You do not have the right permissions to view this record.
404 Not Found -- The specified record could not be found.
405 Method Not Allowed -- You tried to access a record with an invalid method.
406 Not Acceptable -- You requested a format that isn't json.
410 Gone -- The record requested has been removed from our servers.
418 I'm a teapot!
429 Too Many Requests -- You're requesting too many things! Slow down!
500 Internal Server Error -- We had a problem with our server. Try again later.
503 Service Unavailable -- We're temporarily offline for maintenance. Please try again later.