investec-pb-api
Version:
A simple package for interacting with Investec's private banking API
255 lines (252 loc) • 8.53 kB
JavaScript
;
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
// If the importer is in node compatibility mode or this is not an ESM
// file that has been converted to a CommonJS file using a Babel-
// compatible transform (i.e. "__esModule" has not been set), then set
// "default" to the CommonJS "module.exports" for node compatibility.
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
// src/index.ts
var index_exports = {};
__export(index_exports, {
InvestecPbApi: () => InvestecPbApi
});
module.exports = __toCommonJS(index_exports);
// src/investec-pb-api.ts
var import_node_fetch = __toESM(require("node-fetch"), 1);
var createEndpoint = (host, path) => new URL(path, host).toString();
var InvestecPbApi = class {
host;
clientId;
clientSecret;
apiKey;
token;
expiresIn;
/**
* Create a new InvestecPbApi instance.
* @param clientId OAuth client ID
* @param clientSecret OAuth client secret
* @param apiKey API key from Investec
* @param host Optional API host (defaults to Investec production)
*/
constructor(clientId, clientSecret, apiKey, host = "https://openapi.investec.com") {
this.host = host;
this.apiKey = apiKey;
this.clientId = clientId;
this.clientSecret = clientSecret;
this.expiresIn = /* @__PURE__ */ new Date();
}
/**
* Get a valid OAuth token, refreshing if necessary.
* @returns Access token string
*/
async getToken() {
const now = /* @__PURE__ */ new Date();
if (this.token) {
if (now.getTime() < this.expiresIn.getTime()) {
return this.token;
}
}
const result = await this.getAccessToken();
now.setSeconds(now.getSeconds() + result.expires_in);
this.expiresIn = now;
return result.access_token;
}
/**
* Request a new OAuth access token from Investec.
* @returns AuthResponse object
* @throws Error if authentication fails
*/
async getAccessToken() {
const endpoint = createEndpoint(this.host, `/identity/v2/oauth2/token`);
const response = await (0, import_node_fetch.default)(endpoint, {
method: "POST",
headers: {
Authorization: "Basic " + Buffer.from(this.clientId + ":" + this.clientSecret).toString(
"base64"
),
"x-api-key": this.apiKey,
"content-type": "application/x-www-form-urlencoded"
},
body: "grant_type=client_credentials"
});
if (response.status !== 200) {
throw new Error(response.statusText);
}
const result = await response.json();
this.token = result.access_token;
return result;
}
/**
* Make multiple transfers from an account.
* @param accountId The account ID to transfer from
* @param transfers One or more transfer instructions
* @returns TransferResponse
* @throws Error if parameters are missing or API call fails
*/
async transferMultiple(accountId, transfers) {
if (!accountId || !transfers) {
throw new Error("Missing required parameters");
}
const endpoint = createEndpoint(
this.host,
`/za//pb/v1/accounts/${encodeURIComponent(accountId)}/transfermultiple`
);
const token = this.token || await this.getToken();
if (!Array.isArray(transfers)) {
transfers = [transfers];
}
const payload = {
transferList: transfers
};
return fetchPost(endpoint, token, payload);
}
/**
* Make multiple payments from an account.
* @param accountId The account ID to pay from
* @param payments One or more payment instructions
* @returns TransferResponse
* @throws Error if parameters are missing or API call fails
*/
async payMultiple(accountId, payments) {
if (!accountId || !payments) {
throw new Error("Missing required parameters");
}
const endpoint = createEndpoint(
this.host,
`/za//pb/v1/accounts/${encodeURIComponent(accountId)}/paymultiple`
);
const token = this.token || await this.getToken();
if (!Array.isArray(payments)) {
payments = [payments];
}
const payload = {
paymentList: payments
};
return fetchPost(endpoint, token, payload);
}
/**
* Retrieve all beneficiaries for the authenticated user.
* @returns BeneficiaryResponse
*/
async getBeneficiaries() {
const endpoint = createEndpoint(
this.host,
`/za/pb/v1/accounts/beneficiaries`
);
const token = this.token || await this.getToken();
return fetchGet(endpoint, token);
}
/**
* Retrieve all accounts for the authenticated user.
* @returns AccountResponse
*/
async getAccounts() {
const endpoint = createEndpoint(this.host, `/za/pb/v1/accounts`);
const token = this.token || await this.getToken();
return fetchGet(endpoint, token);
}
/**
* Get the balance for a specific account.
* @param accountId The account ID
* @returns AccountBalanceResponse
* @throws Error if accountId is missing or API call fails
*/
async getAccountBalances(accountId) {
if (!accountId) {
throw new Error("Missing required parameters");
}
const endpoint = createEndpoint(
this.host,
`/za/pb/v1/accounts/${encodeURIComponent(accountId)}/balance`
);
const token = this.token || await this.getToken();
return fetchGet(endpoint, token);
}
/**
* Get transactions for a specific account, optionally filtered by date and type.
* @param accountId The account ID
* @param fromDate Optional start date (YYYY-MM-DD)
* @param toDate Optional end date (YYYY-MM-DD)
* @param transactionType Optional transaction type filter
* @returns AccountTransactionResponse
* @throws Error if accountId is missing or API call fails
*/
async getAccountTransactions(accountId, fromDate = null, toDate = null, transactionType = null) {
if (!accountId) {
throw new Error("Missing required parameters");
}
let url = `/za/pb/v1/accounts/${encodeURIComponent(
accountId
)}/transactions`;
const params = new URLSearchParams();
if (fromDate) params.append("fromDate", fromDate);
if (toDate) params.append("toDate", toDate);
if (transactionType) params.append("transactionType", transactionType);
if ([fromDate, toDate, transactionType].some(Boolean)) {
url += `?${params.toString()}`;
}
const endpoint = createEndpoint(this.host, url);
const token = this.token || await this.getToken();
return fetchGet(endpoint, token);
}
};
async function fetchGet(endpoint, token) {
const response = await (0, import_node_fetch.default)(endpoint, {
method: "GET",
signal: AbortSignal.timeout(3e4),
headers: {
Authorization: "Bearer " + token,
"content-type": "application/json"
}
});
if (response.status !== 200) {
if (response.status === 404) {
throw new Error("Card not found");
}
throw new Error(response.statusText);
}
return await response.json();
}
async function fetchPost(endpoint, token, body) {
const response = await (0, import_node_fetch.default)(endpoint, {
method: "POST",
signal: AbortSignal.timeout(3e4),
headers: {
Authorization: "Bearer " + token,
"content-type": "application/json"
},
body: JSON.stringify(body)
});
if (response.status !== 200) {
if (response.status === 404) {
throw new Error("Card not found");
}
throw new Error(response.statusText);
}
return await response.json();
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
InvestecPbApi
});