Skip to content

Node.js Scripts

Write standalone Node.js scripts with bkper-js for complex logic, bulk data operations, scheduled jobs, and integrations that go beyond what the CLI alone can do.

For tasks that go beyond CLI piping — complex logic, external API integration, scheduled jobs — write a Node.js script with bkper-js.

Setup

Terminal window
# Create a script project
mkdir my-bkper-script && cd my-bkper-script
npm init -y
npm install bkper-js bkper

Authenticate once via the CLI:

Terminal window
bkper auth login

The pattern

Every script follows the same structure: authenticate, get a book, do work.

import { Bkper } from 'bkper-js';
import { getOAuthToken } from 'bkper';
Bkper.setConfig({
oauthTokenProvider: async () => getOAuthToken(),
});
const bkper = new Bkper();
const book = await bkper.getBook('your-book-id');
// Your logic here

Examples

Export balances to JSON

import { Bkper } from 'bkper-js';
import { getOAuthToken } from 'bkper';
import { writeFileSync } from 'fs';
Bkper.setConfig({
oauthTokenProvider: async () => getOAuthToken(),
});
const bkper = new Bkper();
const book = await bkper.getBook('your-book-id');
const report = await book.getBalancesReport('on:2025-12-31');
const rows = report.getBalancesContainers().map(container => ({
name: container.getName(),
balance: container.getCumulativeBalance().toString(),
}));
writeFileSync('balances.json', JSON.stringify(rows, null, 2));
console.log(`Exported ${rows.length} balances`);

Bulk-create accounts from a JSON export

import { Account, Bkper } from 'bkper-js';
import { getOAuthToken } from 'bkper';
import { readFileSync } from 'fs';
type AccountInput = {
name: string;
type: 'ASSET' | 'LIABILITY' | 'INCOMING' | 'OUTGOING';
groups?: Array<{ id?: string; name?: string }>;
};
Bkper.setConfig({
oauthTokenProvider: async () => getOAuthToken(),
});
const bkper = new Bkper();
const book = await bkper.getBook('your-book-id');
const data: AccountInput[] = JSON.parse(readFileSync('accounts.json', 'utf-8'));
const accounts = data.map(acc => {
const account = new Account(book).setName(acc.name).setType(acc.type);
if (acc.groups?.length) {
account.setGroups(acc.groups);
}
return account;
});
const created = await book.batchCreateAccounts(accounts);
console.log(`Created ${created.length} accounts`);

Query transactions and generate a report

import { Amount, Bkper } from 'bkper-js';
import { getOAuthToken } from 'bkper';
Bkper.setConfig({
oauthTokenProvider: async () => getOAuthToken(),
});
const bkper = new Bkper();
const book = await bkper.getBook('your-book-id');
const result = await book.listTransactions('account:Expenses after:2025-01-01');
let total = new Amount(0);
for (const tx of result.getItems()) {
const amount = tx.getAmount();
if (!amount) continue;
total = total.plus(amount);
console.log(`${tx.getDate()} | ${tx.getDescription()} | ${amount.toString()}`);
}
console.log(`\nTotal: ${total.toString()}`);

Scheduled jobs

With cron

Terminal window
# Run daily at 8am
0 8 * * * cd /path/to/script && node export.mjs

In CI environments

The CLI helper getOAuthToken() is designed for local developer machines, where the CLI can store and refresh credentials. In GitHub Actions or other unattended environments, provide your own token source:

import { Bkper } from 'bkper-js';
const bkper = new Bkper({
oauthTokenProvider: async () => {
const token = process.env.BKPER_OAUTH_TOKEN;
if (!token) {
throw new Error('BKPER_OAUTH_TOKEN is not set');
}
return token;
},
});

Use this pattern only when another system is already issuing and rotating the token for the job. For unattended long-running automation, implement your own OAuth flow instead of relying on the CLI’s locally stored credentials.

Error handling

Wrap API calls with proper error handling:

import { BkperError } from 'bkper-js';
try {
const book = await bkper.getBook('your-book-id');
// ...
} catch (error) {
if (error instanceof BkperError && error.code === 404) {
console.error('Book not found');
} else if (error instanceof BkperError && error.code === 403) {
console.error('No access to this book');
} else if (error instanceof Error) {
console.error('API error:', error.message);
} else {
console.error('Unknown error:', String(error));
}
process.exit(1);
}

When to use scripts vs apps

ScenarioUse
One-off data migrationScript
Scheduled export/reportScript
Reacting to book events in real timePlatform app
Custom UI for usersPlatform app
Complex multi-step workflow with external APIsScript or app, depending on trigger

Next steps