UNPKG

up-bank-api

Version:

The Up Bank API TypeScript wrapper

380 lines (366 loc) 13.9 kB
import axios from 'axios'; /** * Up API base URL. */ const BASE_URL = 'https://api.up.com.au/api/v1/'; /** * Up API endpoint routes. */ const ENDPOINTS = { ACCOUNTS: 'accounts', CATEGORIES: 'categories', TAGS: 'tags', TRANSACTIONS: 'transactions', WEBHOOKS: 'webhooks', UTIL: 'util', }; /** * Some endpoints exist not to expose data, but to test the API itself. * Currently there is only one endpoint in this group: ping! */ class UtilApi { constructor(api) { this.api = api; } /** * Make a basic ping request to the API. * This is useful to verify that authentication is functioning correctly. * On authentication success an HTTP 200 status is returned. * On failure an HTTP 401 error response is returned. */ ping() { return this.api.get(`${ENDPOINTS.UTIL}/ping`); } } /** * Accounts represent the underlying store used to track balances and the transactions * that have occurred to modify those balances over time. Up currently has two types of * account: SAVER - used to earn interest and to hit savings goals, and * TRANSACTIONAL - used for everyday spending. */ class AccountsApi { constructor(api) { this.api = api; } /** * Retrieve a paginated list of all accounts for the currently authenticated user. * The returned list is paginated and can be scrolled by following the prev and next links where present. */ list(params = {}) { const urlParams = []; if (params.pageSize) { urlParams.push(`page[size]=${params.pageSize}`); } return this.api.get(`${ENDPOINTS.ACCOUNTS}?${urlParams.join('&')}`); } /** * Retrieve a specific account by providing its unique identifier. * @param accountId The unique identifier for the account. e.g. e7a729f0-aaa7-4d6a-b231-f794c0155e1d */ retrieve(accountId) { return this.api.get(`${ENDPOINTS.ACCOUNTS}/${accountId}`); } } /** * Categories enable understanding where your money goes by driving powerful insights in Up. * All categories in Up are pre-defined and are automatically assigned to new purchases in most cases. * A parent-child relationship is used to represent categories, however parent categories cannot be * directly assigned to transactions. */ class CategoriesApi { constructor(api) { this.api = api; } /** * Retrieve a list of all categories and their ancestry. The returned list is not paginated. */ list(params = {}) { const urlParams = []; if (params.parent) { urlParams.push(`filter[parent]=${params.parent}`); } return this.api.get(`${ENDPOINTS.CATEGORIES}?${urlParams.join('&')}`); } /** * Retrieve a specific category by providing its unique identifier. * @param categoryId The unique identifier for the category. e.g. restaurants-and-cafes */ retrieve(categoryId) { return this.api.get(`${ENDPOINTS.CATEGORIES}/${categoryId}`); } } class UpClient { constructor(apiKey = null) { this.api = null; if (null !== apiKey) { this.updateApiKey(apiKey); } } updateApiKey(apiKey) { this.api = axios.create({ baseURL: BASE_URL, timeout: 5000, headers: { Accept: 'application/json', 'Content-Type': 'application/json', Authorization: `Bearer ${apiKey}`, }, }); } processLink(link) { if (link) { const linkFunc = async () => { const parsedLink = link.slice(BASE_URL.length); return await this.get(parsedLink); }; linkFunc.bind(this); return linkFunc; } return null; } async get(url) { const res = await this.getApi().get(url); const linksProcessObj = res.data; /* * If links exist, process the strings into functions that * re-execute 'this.get()' with the new url */ if (linksProcessObj.links) { linksProcessObj.links.next = this.processLink(linksProcessObj.links.next); linksProcessObj.links.prev = this.processLink(linksProcessObj.links.prev); } return res.data; } async post(url, payload) { const res = await this.getApi().post(url, { data: payload }); return res.data; } async delete(url, payload) { const res = await this.getApi().delete(url, { data: { data: payload } }); return res.data; } getApi() { if (null == this.api) { throw new Error('You must specify an apiKey first, try calling updateApi().'); } return this.api; } } /** * Transactions represent the movement of money into and out of an account. They have many * characteristics that vary depending on the kind of transaction. Transactions may be temporarily * HELD (pending) or SETTLED, typically depending on which payment method was used at the point of sale. */ class TransactionsApi { constructor(api) { this.api = api; } /** * Retrieve a list of all transactions across all accounts for the currently authenticated user. * The returned list is paginated and can be scrolled by following the next and prev links where present. * To narrow the results to a specific date range pass one or both of filter[since] and filter[until] in * the query string. These filter parameters should not be used for pagination. Results are ordered * newest first to oldest last. */ list(params = {}) { const urlParams = this.createUrlParams(params); return this.api.get(`${ENDPOINTS.TRANSACTIONS}?${urlParams.join('&')}`); } /** * Retrieve a specific transaction by providing its unique identifier. * @param transactionId The unique identifier for the transaction. e.g. 58c28694-4639-4992-94f3-b030bdb06a8e */ retrieve(transactionId) { return this.api.get(`${ENDPOINTS.TRANSACTIONS}/${transactionId}`); } /** * Retrieve a list of all transactions for a specific account. The returned list is paginated and can be * scrolled by following the next and prev links where present. To narrow the results to a specific date * range pass one or both of filter[since] and filter[until] in the query string. These filter parameters * should not be used for pagination. Results are ordered newest first to oldest last. * @param accountId The unique identifier for the account. e.g. 7a2dfb6f-4c5c-47db-9a95-8794b1ae1470 */ listByAccount(accountId, params = {}) { const urlParams = this.createUrlParams(params); return this.api.get(`/accounts/${accountId}/${ENDPOINTS.TRANSACTIONS}?${urlParams.join('&')}`); } createUrlParams(params) { const urlParams = []; if (params.pageSize) { urlParams.push(`page[size]=${params.pageSize}`); } if (params.filterStatus) { urlParams.push(`filter[status]=${params.filterStatus}`); } if (params.filterSince) { urlParams.push(`filter[since]=${params.filterSince}`); } if (params.filterUntil) { urlParams.push(`filter[until]=${params.filterUntil}`); } if (params.filterCategory) { urlParams.push(`filter[category]=${params.filterCategory}`); } if (params.filterTag) { urlParams.push(`filter[tag]=${params.filterTag}`); } return urlParams; } } /** * Tags are custom labels that can be associated with transactions on Up. Within * the Up application, tags provide additional insight into spending. For * example, you could have a "Take Away" tag that you apply to purchases from * food delivery services. The Up API allows you to manage the tags associated * with transactions. Each transaction may have up to 6 tags. */ class TagsApi { constructor(api) { this.api = api; } /** * Retrieve a list of all tags currently in use. The returned list is not * paginated. */ list(params = {}) { const urlParams = []; if (params.pageSize) { urlParams.push(`page[size]=${params.pageSize}`); } return this.api.get(`${ENDPOINTS.TAGS}?${urlParams.join('&')}`); } /** * Associates one or more tags with a specific transaction. No more than 6 * tags may be present on any single transaction. Duplicate tags are silently * ignored. * @param transactionId The unique identifier for the transaction. e.g. * 0a3c4bdd-1de5-4b9b-bf9e-53fb0b5f2cd7 * @param tags The tags to add to the transaction. */ addTagsToTransaction(transactionId, tags) { return this.api.post(TagsApi.buildTransactionTagsPath(transactionId), tags); } /** * Disassociates one or more tags from a specific transaction. Tags that are * not associated are silently ignored. * @param transactionId The unique identifier for the transaction. e.g. * 0a3c4bdd-1de5-4b9b-bf9e-53fb0b5f2cd7 * @param tags The tags to remove from the transaction. */ removeTagsFromTransaction(transactionId, tags) { return this.api.delete(TagsApi.buildTransactionTagsPath(transactionId), tags); } /** * Build API path to access the tags for a given transaction. * @param transactionId The unique identifier for the transaction. e.g. * 0a3c4bdd-1de5-4b9b-bf9e-53fb0b5f2cd7 */ static buildTransactionTagsPath(transactionId) { return `${ENDPOINTS.TRANSACTIONS}/${transactionId}/relationships/tags`; } } /** * Webhooks provide a mechanism for a configured URL to receive events when * transaction activity occurs on Up. You can think of webhooks as being like * push notifications for your server-side application. */ class WebhookApi { constructor(api) { this.api = api; } /** * Retrieve a list of configured webhooks. The returned list is not * paginated. */ list(params = {}) { const urlParams = []; if (params.pageSize) { urlParams.push(`page[size]=${params.pageSize}`); } return this.api.get(`${ENDPOINTS.WEBHOOKS}?${urlParams.join('&')}`); } /** * Create a new webhook with a given URL. The URL will receive webhook events * as JSON-encoded POST requests. The URL must respond with a HTTP 200 status * on success. * @param url The URL that this webhook should post events to. This must be a * valid HTTP or HTTPS URL that does not exceed 300 characters in length. * @param description An optional description for this webhook, up to 64 * characters in length. */ create(url, description) { const data = { attributes: { url, description: description !== null && description !== void 0 ? description : null, }, }; return this.api.post(ENDPOINTS.WEBHOOKS, data); } /** * Retrieve a specific webhook by providing its unique identifier. * @param id The unique identifier for the webhook. e.g. * a3f1e92b-b790-42cf-afe7-6f4efad9fa9d */ retrieve(id) { return this.api.get(`${ENDPOINTS.WEBHOOKS}/${id}`); } /** * Delete a specific webhook by providing its unique identifier. Once deleted, * webhook events will no longer be sent to the configured URL. * @param id The unique identifier for the webhook. e.g. * a3f1e92b-b790-42cf-afe7-6f4efad9fa9d */ delete(id) { return this.api.delete(`${ENDPOINTS.WEBHOOKS}/${id}`); } /** * Send a `PING` event to a webhook by providing its unique identifier. This is * useful for testing and debugging purposes. The event is delivered *hronously and its data is returned in the response to this request * @param id The unique identifier for the webhook. e.g. * a3f1e92b-b790-42cf-afe7-6f4efad9fa9d */ ping(id) { return this.api.post(`${ENDPOINTS.WEBHOOKS}/${id}/ping`); } } function isUpApiError(e) { if (!(e instanceof Error)) { return false; } const axiosError = e; if (!axiosError.isAxiosError) { return false; } const response = axiosError.response; if (response === undefined) { return false; } return response.data !== undefined && response.status !== undefined; } var AccountTypeEnum; (function (AccountTypeEnum) { AccountTypeEnum["saver"] = "SAVER"; AccountTypeEnum["transactional"] = "TRANSACTIONAL"; })(AccountTypeEnum || (AccountTypeEnum = {})); var TransactionTypeEnum; (function (TransactionTypeEnum) { TransactionTypeEnum["held"] = "HELD"; TransactionTypeEnum["settled"] = "SETTLED"; })(TransactionTypeEnum || (TransactionTypeEnum = {})); class UpApi { constructor(apiKey = null) { this.api = new UpClient(apiKey); this.util = new UtilApi(this.api); this.accounts = new AccountsApi(this.api); this.categories = new CategoriesApi(this.api); this.transactions = new TransactionsApi(this.api); this.tags = new TagsApi(this.api); this.webhooks = new WebhookApi(this.api); } updateApiKey(apiKey) { this.api.updateApiKey(apiKey); } } export { AccountTypeEnum, TransactionTypeEnum, UpApi, isUpApiError };