Skip to main content

SDK & CLI

Frihet provides an official TypeScript SDK and a CLI to manage your business from code or terminal. Both packages are published on npm.

PackagenpmUsage
@frihet/sdknpmSDK for Node.js / TypeScript
frihetnpmTerminal CLI

Installation

SDK

npm install @frihet/sdk

CLI

npm install -g frihet

Authentication

You need an API key. Generate one in Settings > Security at app.frihet.io. Keys start with fri_.

SDK

import Frihet from '@frihet/sdk';

const frihet = new Frihet({
apiKey: 'fri_live_...',
});

Additional options:

OptionTypeDefaultDescription
apiKeystring--Your API key (required)
baseUrlstringhttps://api.frihet.io/v1API base URL
timeoutnumber30000Timeout in milliseconds

CLI

frihet login
# Enter your API key interactively

# Or directly:
frihet login --key fri_live_...

The key is saved to ~/.frihet/config.json with 0600 permissions. You can also use the FRIHET_API_KEY environment variable.


SDK — Quick start

List invoices

import Frihet from '@frihet/sdk';

const frihet = new Frihet({ apiKey: 'fri_live_...' });

const page = await frihet.invoices.list({ limit: 10, status: 'paid' });
console.log(`${page.total} paid invoices`);

for (const inv of page.data) {
console.log(`${inv.documentNumber}${inv.clientName}${inv.total}`);
}

Create an invoice

const invoice = await frihet.invoices.create({
clientName: 'Acme Inc.',
items: [
{ description: 'Consulting', quantity: 10, unitPrice: 150 },
{ description: 'Web development', quantity: 1, unitPrice: 3000 },
],
taxRate: 21,
dueDate: '2026-04-15',
});

console.log(`Invoice ${invoice.documentNumber} created (${invoice.total} EUR)`);

Search and update

// Text search
const results = await frihet.clients.search('Acme');

// Update a client
await frihet.clients.update(results.data[0].id, {
email: 'new@acme.com',
fiscalZone: 'peninsula',
});

Mark invoice as paid and send by email

await frihet.invoices.markPaid('inv_abc123');

await frihet.invoices.send('inv_abc123', {
recipientEmail: 'client@acme.com',
locale: 'en',
});

CLI — Quick start

Check business status

frihet status
# Revenue: EUR 12,500.00
# Expenses: EUR 3,200.00
# Net: EUR 9,300.00

frihet status --month 2026-02

Manage invoices

# List invoices
frihet invoices list --status paid --limit 5

# Search
frihet invoices list -q "Acme"

# View details
frihet invoices get inv_abc123

# Create invoice
frihet invoices create --client "Acme Inc." --item "Consulting,10,150" --tax 21

# Mark as paid
frihet invoices paid inv_abc123

# Send by email
frihet invoices send inv_abc123 --to client@acme.com

Manage expenses

# List expenses
frihet expenses list --from 2026-01-01 --to 2026-03-31

# Create expense
frihet expenses create --desc "Monthly hosting" --amount 49.99 --category software --vendor "Hetzner"

Manage clients

# List clients
frihet clients list

# Search
frihet clients list -q "Acme"

# Create client
frihet clients create --name "Acme Inc." --email info@acme.com --tax-id B12345678 --zone peninsula

Available resources

The SDK exposes the following resources as properties of the Frihet instance:

ResourcePropertyMethods
Invoicesfrihet.invoiceslist, retrieve, create, update, del, search, markPaid, send, pdf, createBatch
Expensesfrihet.expenseslist, retrieve, create, update, del, search, createBatch
Clientsfrihet.clientslist, retrieve, create, update, del, search
Vendorsfrihet.vendorslist, retrieve, create, update, del, search
Productsfrihet.productslist, retrieve, create, update, del, search
Quotesfrihet.quoteslist, retrieve, create, update, del, search, pdf, send
Webhooksfrihet.webhookslist, retrieve, create, update, del + verifySignature (static)
Intelligencefrihet.intelligencecontext, summary, monthly, quarterly

All list and search methods return a Page<T> object:

interface Page<T> {
data: T[];
total: number;
limit: number;
offset: number;
}

Error handling

The SDK throws typed errors for each failure type:

import Frihet, { AuthenticationError, NotFoundError, ValidationError, RateLimitError, TimeoutError } from '@frihet/sdk';

try {
await frihet.invoices.retrieve('does-not-exist');
} catch (err) {
if (err instanceof NotFoundError) {
console.log('Invoice not found');
} else if (err instanceof AuthenticationError) {
console.log('Invalid API key');
} else if (err instanceof ValidationError) {
console.log('Invalid data:', err.message, err.details);
} else if (err instanceof RateLimitError) {
console.log(`Rate limited. Retry in ${err.retryAfter}s`);
} else if (err instanceof TimeoutError) {
console.log('Request timed out');
}
}
ClassHTTP codeWhen
AuthenticationError401Invalid or missing API key
NotFoundError404Resource not found
ValidationError400 / 422Invalid input data
RateLimitError429Request limit exceeded
TimeoutError--No response within configured timeout
APIErrorOtherGeneric server error

Automatic retries

The SDK automatically retries requests that receive 429 (rate limit) or 5xx (server error) status codes, up to 3 times with exponential backoff. No need to implement retry logic yourself.


Idempotency

For create operations, you can send an idempotencyKey to prevent duplicates on retries:

await frihet.invoices.create(
{ clientName: 'Acme Inc.', items: [{ description: 'Service', quantity: 1, unitPrice: 500 }] },
{ idempotencyKey: 'my-unique-key-123' }
);

Webhook verification

The SDK includes a static method to verify the HMAC-SHA256 signature of webhooks:

import { Webhooks } from '@frihet/sdk';

const isValid = Webhooks.verifySignature(
rawBody, // string or Buffer of the body
req.headers['x-frihet-signature'], // signature header
'whsec_your_secret', // webhook secret
);

Environment variables

VariableDescription
FRIHET_API_KEYAPI key (alternative to frihet login in CLI or the SDK constructor)
FRIHET_API_URLCustom base URL

More information