# 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.

| Package | npm | Usage |
|---------|-----|-------|
| `@frihet/sdk` | [![npm](https://img.shields.io/npm/v/@frihet/sdk)](https://www.npmjs.com/package/@frihet/sdk) | SDK for Node.js / TypeScript |
| `frihet` | [![npm](https://img.shields.io/npm/v/frihet)](https://www.npmjs.com/package/frihet) | Terminal CLI |

---

## Installation

### SDK

```bash
npm install @frihet/sdk
```

### CLI

```bash
npm install -g frihet
```

---

## Authentication

You need an API key. Generate one in **Settings > Security** at [app.frihet.io](https://app.frihet.io/settings/security?utm_source=frihet_io&utm_medium=docs&utm_campaign=docs_cta). Keys start with `fri_`.

### SDK

```typescript

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

Additional options:

| Option | Type | Default | Description |
|--------|------|---------|-------------|
| `apiKey` | `string` | -- | Your API key (required) |
| `baseUrl` | `string` | `https://api.frihet.io/v1` | API base URL |
| `timeout` | `number` | `30000` | Timeout in milliseconds |

### CLI

```bash
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

```typescript

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

```typescript
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

```typescript
// 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

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

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

---

## CLI — Quick start

### Check business status

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

frihet status --month 2026-02
```

### Manage invoices

```bash
# 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

```bash
# 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

```bash
# 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:

| Resource | Property | Methods |
|----------|----------|---------|
| Invoices | `frihet.invoices` | `list`, `retrieve`, `create`, `update`, `del`, `search`, `markPaid`, `send`, `pdf`, `createBatch` |
| Expenses | `frihet.expenses` | `list`, `retrieve`, `create`, `update`, `del`, `search`, `createBatch` |
| Clients | `frihet.clients` | `list`, `retrieve`, `create`, `update`, `del`, `search` |
| Vendors | `frihet.vendors` | `list`, `retrieve`, `create`, `update`, `del`, `search` |
| Products | `frihet.products` | `list`, `retrieve`, `create`, `update`, `del`, `search` |
| Quotes | `frihet.quotes` | `list`, `retrieve`, `create`, `update`, `del`, `search`, `pdf`, `send` |
| Webhooks | `frihet.webhooks` | `list`, `retrieve`, `create`, `update`, `del` + `verifySignature` (static) |
| Intelligence | `frihet.intelligence` | `context`, `summary`, `monthly`, `quarterly` |

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

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

---

## Error handling

The SDK throws typed errors for each failure type:

```typescript

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');
  }
}
```

| Class | HTTP code | When |
|-------|-----------|------|
| `AuthenticationError` | 401 | Invalid or missing API key |
| `NotFoundError` | 404 | Resource not found |
| `ValidationError` | 400 / 422 | Invalid input data |
| `RateLimitError` | 429 | Request limit exceeded |
| `TimeoutError` | -- | No response within configured timeout |
| `APIError` | Other | Generic 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:

```typescript
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:

```typescript

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

| Variable | Description |
|----------|-------------|
| `FRIHET_API_KEY` | API key (alternative to `frihet login` in CLI or the SDK constructor) |
| `FRIHET_API_URL` | Custom base URL |

---

## More information

- [REST API](/desarrolladores/api-rest) — full endpoint reference
- [Webhooks](/desarrolladores/webhooks) — events and signature verification
- [GitHub repository](https://github.com/Frihet-io/frihet-sdk) — source code, issues, contributions
- [npm @frihet/sdk](https://www.npmjs.com/package/@frihet/sdk) | [npm frihet](https://www.npmjs.com/package/frihet)
