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:
- Should we call "institutions", "platforms"?
- Should we rather just use terms like "where" (institution) and "what" (asset)?
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:
- Should be able to retrieve all portfolios for a single user.
- In the future, a portfolio could belong to a group.
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:
- 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".
- 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:
- 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".
- 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:
- 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. |