Skip to content

Instantly share code, notes, and snippets.

@tristankenney
Last active February 20, 2021 22:15
Show Gist options
  • Save tristankenney/5cfd024b8eac0b3f79a10b7295e5c17d to your computer and use it in GitHub Desktop.
Save tristankenney/5cfd024b8eac0b3f79a10b7295e5c17d to your computer and use it in GitHub Desktop.
Up Bank + Google Sheets = ❤️
const UP_ACCOUNTS = "https://api.up.com.au/api/v1/accounts";
const UP_TRANSACTIONS = (accountId, params) =>
`https://api.up.com.au/api/v1/accounts/${accountId}/transactions?${params}`;
/**
* Retrieves a list of accounts from Up bank account
*
* @param {string} token Up API token
* @param {bool} [includeSavers=true] Include savers accounts
* @return list of accounts
* @customfunction
*/
function UpAccounts(token, includeSavers = true) {
const accounts = fetch(UP_ACCOUNTS, token);
const accountFilter = (account) =>
includeSavers || account.attributes.accountType !== "SAVER";
const accountMap = (account) => {
return [
account.id,
account.attributes.displayName,
account.attributes.accountType,
parseFloat(account.attributes.balance.value),
];
};
return [["Account ID", "Name", "Type", "Balance"]].concat(
accounts.data.filter(accountFilter).map(accountMap)
);
}
/**
* Retrieves a list of transactions from Up bank account
*
* @param {string} token Up API token
* @param {string} accountId account to retrieve transactions from
* @param {Date} since
* @param {Date} until
* @param {string|Array<string>|Array<Array<string>>} transactionTypes=['Transaction', 'Quick save', 'Cover', 'Transfer', 'Funding', 'Forward'] included transactions
* @param {boolean} includeRaw=false include raw JSON
* @return list of transactions'
* @customfunction
*/
function UpTransactions(
token,
accountId,
since = null,
until = null,
transactionTypes = [
"Transaction",
"Quick save",
"Cover",
"Transfer",
"Funding",
"Forward",
],
includeRaw = false
) {
transactionTypes =
typeof transactionTypes === "string"
? transactionTypes.split(",")
: transactionTypes;
transactionTypes = Array.isArray(transactionTypes)
? transactionTypes.flat()
: [transactionTypes];
const params = {
"page[size]": () => 100,
"filter[since]": () => (since instanceof Date ? since.toISOString() : null),
"filter[until]": () => (until instanceof Date ? until.toISOString() : null),
};
const encodedParams = Object.entries(params)
.filter(([key, value]) => value())
.map(([key, value]) => {
return `${encodeURIComponent(key)}=${encodeURIComponent(value())}`;
})
.join("&");
const getTransactionType = (transaction) => {
const description = transaction.attributes.description;
const rawText = transaction.attributes.rawText;
const amount = transaction.attributes.amount;
const relationships = transaction.relationships;
const types = {
Cover: () => description.startsWith("Cover from"),
Transfer: () =>
description.startsWith("Transfer from") ||
description.startsWith("Transfer to"),
Forward: () => description.startsWith("Forward to"),
"Quick save": () => description.startsWith("Quick save"),
Funding: () =>
amount.valueInBaseUnits > 0 &&
relationships.category.data === null &&
description != rawText,
Transaction: () => true,
};
return Object.entries(types)
.find(([type, test]) => test())
.shift();
};
const transactionFilter = (transaction) =>
transactionTypes.includes(getTransactionType(transaction));
const transactionMap = (transaction) => {
const attributes = transaction.attributes;
const roundUpValue = attributes.roundUp
? attributes.roundUp.amount.value
: 0;
const mappedTransaction = [
attributes.createdAt,
attributes.description,
getTransactionType(transaction),
parseFloat(attributes.amount.value),
parseFloat(roundUpValue),
parseFloat(attributes.amount.value) + parseFloat(roundUpValue),
transaction.relationships.tags.data
.map((tag) => {
return tag.id;
})
.join(","),
];
if (includeRaw) {
mappedTransaction.push(JSON.stringify(transaction));
}
return mappedTransaction;
};
let data = fetch(UP_TRANSACTIONS(accountId, encodedParams), token);
let transactions = data.data;
while (data.links.next) {
data = fetch(data.links.next, token);
transactions = transactions.concat(data.data);
}
const headers = [
"Created At",
"Description",
"Type",
"Amount",
"Round Up",
"Total",
"Tags",
];
if (includeRaw) {
headers.push("JSON");
}
return [headers].concat(
transactions.filter(transactionFilter).map(transactionMap)
);
}
function fetch(url, token) {
const options = {
method: "GET",
headers: {
Authorization: `Bearer ${token}`,
},
};
const response = UrlFetchApp.fetch(url, options);
return JSON.parse(response.getContentText());
}
@tristankenney
Copy link
Author

tristankenney commented Feb 1, 2021

Installation

  1. Head over to https://api.up.com.au/getting_started
  2. Follow the on-screen instructions to claim a token
  3. Grab the generated token (and store it somewhere safe!)
  4. Create a new Google Spreadsheet you'd like to pull in data from Up
  5. Open Tools -> Script Editor
  6. Replace the content of Code.gs file with the above
  7. Click Save
  8. Enjoy

Usage

Once you have installed the script using the installation instructions, you will have two new Google spreadsheet functions, UpAccounts and UpTransactions available to you!

UpAccounts

Basic Usage

=UpAccounts('up:yeah:xxxxx')

Parameters

  • token: your Up API token (begins with up:yeah)
  • includeSavers: Allows you to include or exclude Savers accounts (optional) [default=true]

UpTransactions

Basic Usage

=UpTransactions('up:yeah:xxxxx', 'c62336a0-abf7-4715-ba1e-ba6fac453827')

Parameters

  • token: your Up API token (begins with up:yeah)
  • accountId: account id to retrieve transactions from (a list of these can be found using UpAccounts)
  • since: date since in RFC-3339 format (optional)
  • until: date since in RFC-3339 format (optional)
  • transactionTypes: transaction types to include (optional) [default="Transaction,Quick save,Cover,Transfer,Funding,Forward"]

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment