BeeL Node.js SDK

Official Node.js/TypeScript SDK for the BeeL API — Spanish invoicing for self-employed professionals with VeriFactu compliance.
Node.js 18+. Single dependency (openapi-fetch).
Features
- Full TypeScript types auto-generated from OpenAPI spec
- Automatic retries with exponential backoff on 429 and 5xx
- Auto idempotency keys on every POST request
- Typed errors — catch
BeeLNotFoundError instead of checking status codes
- PDF download as Buffer
- Webhook signature verification with HMAC-SHA256
- Instance-based client — multiple API keys, no global state
- ESM + CommonJS
Installation
npm install @beel_es/sdk
Quick Start
import { BeeL } from '@beel_es/sdk';
const beel = new BeeL({ apiKey: 'beel_sk_live_...' });
const company = beel.company('company-uuid');
const invoice = await company.invoices.create({
type: 'STANDARD',
recipient: { customer_id: 'customer-uuid' },
lines: [
{ line_type: 'NORMAL', description: 'Consulting', quantity: 1, unit_price: 100, discount_percentage: 0 },
],
});
console.log(invoice.id);
const issued = await company.invoices.issue(invoice.id);
console.log(issued.invoice_number);
Companies (multi-NIF)
Every operation on beel.company(companyId) addresses the company in the URL path, so it
works with any number of NIFs and never depends on a session focus:
const company = beel.company('company-uuid');
const { invoices, pagination } = await company.invoices.list({ status: 'ISSUED' });
await company.invoices.issue('invoice-uuid');
await company.invoices.void('invoice-uuid', { reason: 'Billing error' });
await company.invoices.createCorrective('invoice-uuid', { ... });
const pdf = await company.invoices.getPdf('invoice-uuid');
const customer = await company.customers.create({ ... });
const product = await company.products.create({ ... });
await company.series.ensureDefaults();
await company.recurringInvoices.create({ ... });
await company.recurringInvoices.setStatus('rec-uuid', { status: 'PAUSED' });
const summary = await company.fiscalSummary({ year: 2026 });
const readiness = await company.issuingReadiness();
Accounts (managed accounts, members & webhooks)
For integrators managing several accounts (provisioning, gestorías, platforms):
const { accounts } = await beel.accounts.list();
const created = await beel.accounts.provision({ external_ref: 'client-42' });
const account = beel.account(created.account_id);
const { companies } = await account.companies.list();
await account.companies.create({ nif: 'B12345678', ... });
const members = await account.members.list();
await account.members.putGrant('member-id', 'company-id', { permissions: [...] });
await account.invitations.create({ invited_email: 'user@example.com', account_role: 'MEMBER' });
const webhook = await account.webhooks.create({ url: 'https://...', events: ['invoice.issued'] });
await account.webhooks.test(webhook.id);
await account.webhooks.rotateSecret(webhook.id);
const usage = await account.usage();
await account.createClaimToken();
Resources (deprecated session-focus surface)
Deprecated: the API contract marks the whole session-focus surface (beel.invoices,
beel.customers, beel.products, beel.series, beel.configuration) as deprecated.
Prefer the company-scoped equivalents above. These keep working during the sunset window.
const { invoices, pagination } = await beel.invoices.list({ status: 'ISSUED', limit: 20 });
const invoice = await beel.invoices.get('invoice-uuid');
const created = await beel.invoices.create({ ... });
const updated = await beel.invoices.update('id', { ... });
await beel.invoices.delete('id');
await beel.invoices.issue('id');
await beel.invoices.markPaid('id');
await beel.invoices.markSent('id');
await beel.invoices.void('id', { reason: 'Duplicate invoice sent in error' });
await beel.invoices.schedule('id', { scheduled_for: '2026-04-15' });
await beel.invoices.unschedule('id');
await beel.invoices.duplicate('id');
await beel.invoices.createCorrective('id', { ... });
const { customers, pagination } = await beel.customers.list({ search: 'Acme' });
const customer = await beel.customers.create({
legal_name: 'Acme SL',
nif: 'B86561412',
address: { street: 'Calle Mayor', number: '1', postal_code: '28001', city: 'Madrid', province: 'Madrid', country: 'Spain', country_code: 'ES' },
});
const { products } = await beel.products.list();
const results = await beel.products.search('consulting');
const taxConfig = await beel.configuration.getTaxConfig();
const series = await beel.series.list();
const result = await beel.nif.validate('B12345678');
Typed Errors
Every API error maps to a specific error class:
import { BeeL, BeeLNotFoundError, BeeLValidationError } from '@beel_es/sdk';
try {
await beel.invoices.get('nonexistent-id');
} catch (error) {
if (error instanceof BeeLNotFoundError) {
console.log(error.message);
console.log(error.requestId);
}
if (error instanceof BeeLValidationError) {
console.log(error.message);
console.log(error.details);
}
}
BeeLAuthError | 401, 403 | Invalid or missing API key |
BeeLNotFoundError | 404 | Resource doesn't exist |
BeeLValidationError | 422 | Invalid data |
BeeLConflictError | 409 | Duplicate (e.g. same NIF) |
BeeLRateLimitError | 429 | Too many requests (auto-retried) |
BeeLApiError | 5xx | Server error (auto-retried) |
Automatic Retries
429 and 5xx errors are retried with exponential backoff. Client errors (400, 401, 404, 422) are never retried.
const beel = new BeeL({
apiKey: 'beel_sk_live_...',
maxRetries: 5,
retryDelayMs: 1000,
maxRetryDelayMs: 60000,
});
PDF Download
import fs from 'fs';
const { buffer, fileName } = await beel.downloadPdf('invoice-uuid');
fs.writeFileSync(fileName, buffer);
Webhooks
Verify webhook signatures before processing:
import express from 'express';
import { WebhookVerifier } from '@beel_es/sdk';
const verifier = new WebhookVerifier(process.env.BEEL_WEBHOOK_SECRET!);
app.post('/webhooks/beel', express.raw({ type: 'application/json' }), (req, res) => {
try {
const event = verifier.verify(
req.body.toString('utf8'),
req.headers['beel-signature'] as string,
);
if (event.type === 'verifactu.status.updated') {
console.log(event.data.new_status);
}
res.status(200).send('OK');
} catch {
res.status(400).send('Invalid signature');
}
});
Builders
Optional fluent builders for common operations:
import { InvoiceBuilder, CustomerBuilder } from '@beel_es/sdk';
const customer = CustomerBuilder.create()
.name('Acme SL')
.nif('B12345678')
.email('contact@acme.com')
.address('Calle Mayor', '1', '28001', 'Madrid', 'Madrid', 'Spain')
.build();
const invoice = InvoiceBuilder.create()
.forCustomer('customer-uuid')
.addLine('Service A', 5, 100.0)
.addLine('Service B', 3, 150.0)
.metadata({ stripe_id: 'pi_abc123' })
.build();
Environments
const sandbox = new BeeL({ apiKey: 'beel_sk_test_...' });
const prod = new BeeL({ apiKey: 'beel_sk_live_...' });
Full Configuration
const beel = new BeeL({
apiKey: 'beel_sk_live_...',
baseUrl: 'https://app.beel.es/api',
maxRetries: 3,
retryDelayMs: 500,
maxRetryDelayMs: 30000,
});
Documentation
Full API docs: docs.beel.es
License
MIT