@otters/monzo
Version:
Monzo API wrapper
451 lines (447 loc) • 15.5 kB
TypeScript
type Config = {
base: string;
};
type Currency = 'GBP' | 'EUR' | 'USD' | 'AUD' | 'CAD' | 'CHF' | 'CNY' | 'DKK' | 'HKD' | 'JPY' | 'NZD' | 'PLN' | 'RUB' | 'SEK' | 'SGD' | 'THB' | 'TRY' | 'ZAR';
type Pagination = {
limit?: number;
since?: string;
before?: string;
};
type AppCredentials = {
client_id: Id<'oauth2client'>;
client_secret: string;
redirect_uri: string;
};
type UserCredentials = {
access_token: string;
client_id: Id<'oauth2client'>;
expires_in: number;
refresh_token: string;
token_type: 'Bearer';
user_id: Id<'user'>;
};
declare const ID_PREFIXES: readonly ["acc", "pot", "user", "oauth2client", "tx", "grp", "merch", "business", "entryset", "obextpayment", "potdep", "anonuser", "mcauthmsg", "mclifecycle", "mccard", "tab", "participant", "attach", "sub", "potwdr", "copdecision", "series", "p2p", "billsplit", "payreq", "inbndp2p", "trip", "receipt", "webhook"];
type IdPrefixes = (typeof ID_PREFIXES)[number];
type Id<T extends IdPrefixes> = `${T}_${string}`;
type AnyId = Id<IdPrefixes>;
declare function validateId<T extends IdPrefixes>(maybeId: string, prefix: T): maybeId is Id<T>;
declare function validateId(maybeId: string): maybeId is AnyId;
declare function assertId<T extends IdPrefixes>(maybeId: string, prefix: T): asserts maybeId is Id<T>;
declare function assertId(maybeId: string): asserts maybeId is AnyId;
declare function castId<T extends IdPrefixes>(maybeId: string, prefix: T): `${T}_${string}`;
type Hex = `#${string}`;
declare namespace Models {
type TransactionMetadata = Record<string, string>;
type Transaction<Metadata extends TransactionMetadata = TransactionMetadata> = {
account_id: Id<'acc'>;
amount: number;
amount_is_pending: boolean;
atm_fees_detailed: AtmFeesDetailed | null;
attachments: Attachment[] | null;
can_add_to_tab: boolean;
can_be_excluded_from_breakdown: boolean;
can_be_made_subscription: boolean;
can_match_transactions_in_categorization: boolean;
can_split_the_bill: boolean;
/**
* The categories this transaction belongs to.
* Key = name of the category
* Value = amount spent in this category from overall amount spent in this tx
*/
categories: Record<string, number> | null;
category: string;
counterparty: Counterparty;
created: string;
currency: Currency;
dedupe_id: string;
description: string;
fees: Fees;
id: Id<'tx'>;
include_in_spending: boolean;
international: unknown;
is_load: boolean;
labels: string[] | null;
local_amount: number;
local_currency: Currency;
merchant: Id<'merch'> | null;
metadata: Metadata;
notes: string;
originator: boolean;
parent_account_id: '';
scheme: 'uk_retail_pot' | 'payport_faster_payments' | 'mastercard' | 'p2p_payment' | 'topup' | '3dsecure';
settled: string;
updated: string;
user_id: Id<'user'> | '';
decline_reason: 'INSUFFICIENT_FUNDS' | 'CARD_INACTIVE' | 'CARD_BLOCKED' | 'INVALID_CVC' | 'OTHER' | null;
tab: Tab | null;
};
type AtmFeesDetailed = {
allowance_id: string;
allowance_usage_explainer_text: string;
fee_amount: number;
fee_currency: Currency;
fee_summary: null;
withdrawal_amount: number;
withdrawal_currency: Currency;
};
type Attachment = {
created: string;
external_id: Id<'tx'>;
file_type: string;
file_url: string;
id: Id<'attach'>;
type: string;
url: string;
user_id: Id<'user'>;
};
type Counterparty = {
account_number?: string;
name?: string;
sort_code?: string;
user_id?: Id<'user' | 'anonuser'>;
beneficiary_account_type?: string;
account_id?: Id<'acc'>;
preferred_name?: string;
};
type Fees = {};
type Tab = {
created_by: Id<'user'>;
currency: Currency;
id: Id<'tab'>;
item_count: number;
left_participants: unknown[];
modified_at: string;
name: string;
opened_at: string;
participants: Participant[];
status: string;
total: number;
};
type Participant = {
first_name: string;
id: Id<'participant'>;
invited_at?: string;
invited_by?: Id<'user'>;
name: string;
payment_status: string;
settle_amount: number;
settle_currency: Currency;
status: string;
tab_id: Id<'tab'>;
total_amount: number;
total_currency: Currency;
user_id: Id<'user'>;
};
type ExpandedTransaction<Metadata extends TransactionMetadata = TransactionMetadata> = {
merchant: Merchant | null;
} & Omit<Transaction<Metadata>, 'merchant'>;
type Merchant = {
address: Address;
created: string;
group_id: Id<'grp'>;
id: Id<'merch'>;
logo: string;
emoji: string;
name: string;
category: string;
};
type Address = {
address: string;
city: string;
country: string;
latitude: number;
longitude: number;
postcode: string;
region: string;
};
type Account = {
id: Id<'acc'>;
closed: boolean;
created: string;
description: string;
type: 'uk_retail' | 'uk_retail_joint' | 'uk_retail_plus' | 'uk_personal' | 'uk_business' | 'uk_monzo_flex' | 'uk_monzo_flex_backing_loan' | 'uk_rewards';
currency: Currency;
country_code: string;
owners: Array<{
user_id: Id<'user'>;
preferred_name: string;
preferred_first_name: string;
}>;
account_number?: string;
sort_code?: string;
payment_details?: {
iban: {
unformatted: string;
formatted: string;
usage_description: string;
usage_description_web: string;
};
locale_uk: {
account_number: string;
sort_code: string;
};
};
business_id?: Id<'business'>;
};
type ReceiptItem = {
description: string;
quantity: number;
unit: string;
amount: number;
currency: Currency;
tax: number;
sub_items?: Array<Exclude<ReceiptItem, 'sub_items'>>;
};
type ReceiptPayment = {
type: 'card';
bin: string;
last_four: string;
auth_code: string;
aid: string;
mid: string;
tid: string;
amount: number;
currency: Currency;
} | {
type: 'cash';
amount: number;
currency: Currency;
} | {
type: 'gift_card';
gift_card_type: string;
currency: Currency;
};
type ReceiptMerchant = {
name: string;
/**
* Indicates if this merchant is an "online" merchant or brick and mortar.
* true for Ecommerce merchants like Amazon, false for offline merchants like Pret or Starbucks
*/
online: boolean;
phone: string;
email: string;
store_name: string;
store_address: string;
store_postcode: string;
};
type ReceiptTax = {
description: 'VAT';
amount: number;
currency: Currency;
tax_number?: string;
};
type Balance = {
balance: number;
total_balance: number;
balance_including_flexible_savings: number;
currency: Currency;
spend_today: number;
local_currency: '' | Currency;
local_exchange_rate: number;
local_spend: Array<{
spend_today: number;
currency: Currency;
}>;
};
type Pot = {
id: Id<'pot'>;
name: string;
style: string;
balance: number;
currency: Currency;
goal_amount: number;
type: string;
product_id: string;
current_account_id: Id<'acc'>;
cover_image_url: string;
isa_wrapper: string;
round_up: boolean;
round_up_multiplier: number;
is_tax_pot: boolean;
created: string;
updated: string;
deleted: boolean;
locked: boolean;
charity_id: string;
available_for_bills: boolean;
has_virtual_cards: boolean;
};
}
declare namespace Webhooks {
namespace Payloads {
type Payload<T extends string, D> = {
type: T;
data: D;
};
export type TransactionCreated = Payload<'transaction.created', Models.ExpandedTransaction>;
export type TransactionUpdated = Payload<'transaction.updated', Models.ExpandedTransaction>;
export { };
}
type Payload = Payloads.TransactionCreated | Payloads.TransactionUpdated;
}
/**
* The Monzo API client. This class is used to make requests to the Monzo API.
*/
declare class MonzoAPI {
readonly credentials: {
access_token: string;
refresh_token: string;
token_type: string;
} | {
token_type: string;
access_token: string;
};
private readonly app;
private readonly api;
private readonly config;
/**
* Construct a new instance of the Monzo API. If you want to refresh a token, you must
* pass the `refresh_token` as well as the application's credentials to the .refresh() method directly.
*
* @param bearer The access token to use for requests.
*
* @example
* ```ts
* const api = new MonzoAPI('eyJhbGciOiJFUzI1NiIsI...');
* ```
*/
constructor(bearer: string);
/**
* Construct a new instance of the Monzo API with full credentials. This overload
* exists so you can call the .refresh() method without having to pass the app credentials or refresh_token.
*
* @param credentials Full credentials to use for requests.
* @param app The app credentials to use for refreshing tokens
* @param config Optional configuration for the API (to specify base url, etc.)
*
* @example
* ```ts
* const credentials = {
* access_token: 'eyJhbGciOiJFUzI1NiIsI...',
* refresh_token: '...',
* // ...
* };
* const api = new MonzoAPI();
* ```
*/
constructor(credentials: Pick<UserCredentials, 'access_token' | 'refresh_token'> & Partial<Pick<UserCredentials, 'token_type'>>, app?: AppCredentials, config?: Partial<Config>);
/**
* Calls the logout endpoint. This will immediately invalidate the access token.
* Once invalidated, the user must go through the authentication process again. You will not be able to refresh the access token.
*/
logout(): Promise<void>;
/**
* Refreshes the access token. This will invalidate the current access token and return a new one.
* You'll have to reinstantiate the API client with the new token.
*
* You must pass the full user credentials and app credentials to the constructor, otherwise this method will throw.
*
* @returns The new credentials to use for requests.
*
* @example
* ```ts
* const app: AppCredentials = {
* client_id: 'oauth2client_00001abc...',
* client_secret: '...',
* redirect_uri: '...',
* }
*
* const current = new MonzoAPI(
* {
* access_token: '...',
* refresh_token: '...',
* },
* app,
* );
* const creds = await current.refresh();
* const refreshed = new MonzoAPI(creds, app);
* ```
*/
refresh(): Promise<UserCredentials>;
/**
* Gets information about the authenticated user.
* @returns Information about the authenticated user.
*/
whoami(): Promise<{
authenticated: boolean;
client_id: Id<'oauth2client'>;
user_id: Id<'user'>;
}>;
getAccounts(account_type?: Models.Account['type']): Promise<Models.Account[]>;
getBalance(account_id: Id<'acc'>): Promise<Models.Balance>;
getPots(current_account_id: Id<'acc'>): Promise<Models.Pot[]>;
depositIntoPot(pot: Id<'pot'>, { amount, dedupe_id, source_account_id, }: {
amount: number;
dedupe_id: string;
source_account_id: Id<'acc'>;
}): Promise<Models.Pot>;
withdrawFromPot(pot: Id<'pot'>, { destination_account_id, amount, dedupe_id, }: {
destination_account_id: Id<'acc'>;
amount: number;
dedupe_id: string;
}): Promise<Models.Pot>;
getTransaction<Metadata extends Models.TransactionMetadata>(transaction_id: Id<'tx'>, expand: 'merchant'): Promise<Models.ExpandedTransaction<Metadata>>;
getTransaction<Metadata extends Models.TransactionMetadata>(transaction_id: Id<'tx'>): Promise<Models.Transaction<Metadata>>;
getTransactions(account_id: Id<'acc'>, pagination?: Pagination): Promise<Models.Transaction<Models.TransactionMetadata>[]>;
annotateTransaction<M extends Models.TransactionMetadata>(transaction_id: Id<'tx'>, metadata: M): Promise<Models.Transaction<Omit<M, "notes">>>;
createFeedItem(account_id: Id<'acc'>, type: 'basic', params: {
title: string;
image_url: string;
url?: string;
body?: string;
background_color?: Hex;
title_color?: Hex;
body_color?: Hex;
}): Promise<void>;
uploadAttachment(file_name: string, file_type: string, content_length: number): Promise<{
file_url: string;
upload_url: string;
}>;
registerAttachment(external_id: Id<'tx'>, file_url: string, file_type: string): Promise<{
id: Id<'attach'>;
user_id: Id<'user'>;
external_id: Id<'tx'>;
file_url: string;
file_type: string;
created: string;
}>;
deregisterAttachment(attachment_id: Id<'attach'>): Promise<void>;
createReceipt(transaction_id: Id<'tx'>, receipt: {
items: Models.ReceiptItem[];
external_id: string;
total: number;
currency: Currency;
}): Promise<void>;
retrieveReceipt<E extends string = string>(external_id: E): Promise<{
id: Id<'receipt'>;
external_id: E;
total: number;
currency: Currency;
items: Models.ReceiptItem[];
}>;
deleteReceipt(external_id: string): Promise<void>;
registerWebhook<Account extends Id<'acc'>, Url extends string>(account_id: Account, webhookUrl: Url): Promise<{
account_id: Account;
id: Id<'webhook'>;
url: Url;
}>;
listWebhooks<Account extends Id<'acc'>>(account_id: Account): Promise<{
id: Id<'webhook'>;
account_id: Account;
url: string;
}[]>;
deleteWebhook(id: Id<'webhook'>): Promise<void>;
}
declare class MonzoOAuthAPI {
readonly credentials: AppCredentials;
private readonly api;
private readonly config;
constructor(credentials: AppCredentials, config?: Partial<Config>);
getOAuthURL(): {
state: string;
url: string;
};
getOAuthURL(state: string): string;
exchangeAuthorizationCode(code: string): Promise<MonzoAPI>;
}
export { type AnyId, type AppCredentials, type Config, type Currency, type Hex, ID_PREFIXES, type Id, type IdPrefixes, Models, MonzoAPI, MonzoOAuthAPI, type Pagination, type UserCredentials, Webhooks, assertId, castId, validateId };