@whocomply/ledger
v0.1.2
Published
TypeScript SDK for the WhoComply Ledger API: multi-tenant double-entry ledger for fintechs
Maintainers
Readme
@whocomply/ledger
TypeScript SDK for the WhoComply Ledger API.
npm install @whocomply/ledgerZero runtime dependencies, built on global fetch (Node 18+ and browsers),
dual ESM/CJS output with full type declarations. MIT licensed.
import { LedgerClient, LedgerApiError } from '@whocomply/ledger';
const ledger = new LedgerClient({
baseUrl: 'https://ledger.internal.example.com',
tenant: 'demo-fintech',
apiKey: process.env.LEDGER_API_KEY,
});
// Post a balanced double-entry transaction
const tx = await ledger.transactions.post({
description: 'Customer deposit via bank transfer',
reference: 'DEP-2026-001',
idempotencyKey: 'deposit-evt-8842', // optional; generated when omitted
entries: [
{ account_code: '1000', amount: '250000.00', side: 'debit', currency: 'NGN' },
{ account_code: '2100', amount: '250000.00', side: 'credit', currency: 'NGN' },
],
});
// Balances, current and historical
const now = await ledger.accounts.balance(accountId);
const mayClose = await ledger.accounts.balanceAsOf(accountId, '2026-05-31');
// Reverse (at most once; second attempt raises a 409)
await ledger.transactions.reverse(tx.id);
// Treasury surface
await ledger.currencies.register({ code: 'BTC', exponent: 8, name: 'Bitcoin' });
await ledger.periods.create({ name: 'June 2026', starts_on: '2026-06-01', ends_on: '2026-06-30' });
const tb = await ledger.reports.trialBalance({ asOf: '2026-06-30' });
const csv = await ledger.reports.xeroJournalsCsv({ startDate: '2026-06-01', endDate: '2026-06-30' });Rules the types enforce
- Amounts are strings, always. The ledger stores NUMERIC(38,18); JavaScript numbers cannot represent one wei or one satoshi exactly. Send strings, receive strings.
- Errors are
LedgerApiErrorwithstatus, the server's message, and anisConflicthelper for the 409 family (double reversal, closed period, duplicate currency or period). - The wire format (snake_case) is preserved verbatim; the SDK adds no mapping layer that could drift from the API.
Development
npm install
npm test # unit tests, mocked fetch
npm run build # dual ESM/CJS + d.ts via tsup
npm run smoke # live end-to-end against localhost:8080 (see docs/development.md)