Start free trial
14 days free trial - no credit card needed
Hisab
Pricing
Sales: +212 649 22 43 64
Start free trial

14 days free trial - no credit card needed

Login

SDK

The official TypeScript SDK

hisab-sdk wraps the REST API with full types, auto-pagination, automatic retries and webhook verification.

npm install hisab-sdk|TypeScript|Node.js 18+

Installation

Install from npm. The SDK ships ESM and CommonJS builds with zero production dependencies.

shell
npm install hisab-sdk
# or
yarn add hisab-sdk
# or
pnpm add hisab-sdk

Requires Node.js 18 or newer. Your API key comes from the dashboard: Settings, then API keys.

Quick start

Create a client with your API key, then create and finalize your first invoice.

TypeScript
import Hisab from 'hisab-sdk';

const hisab = new Hisab({ apiKey: process.env.HISAB_API_KEY });

// 1. create a draft invoice
const draft = await hisab.invoices.create({
  customer_id: 'cus_2b81fe',
  issue_date: '2026-06-05',
  items: [
    { description: 'Integration services', quantity: 8, unit_price: 1300, tax_rate: 20 },
  ],
});

// 2. finalize it - this assigns the official invoice number
const invoice = await hisab.invoices.finalize(draft.id);

console.log(invoice.invoice_number); // FAC-2026-0142

Invoices

The full invoice lifecycle: draft, finalize, send, pay, void, plus PDF and UBL 2.1 exports.

TypeScript
// list with filters (paginated)
const { data, meta } = await hisab.invoices.list({ status: 'paid', page: 1 });

// lifecycle
const invoice = await hisab.invoices.get('inv_8f3a91');
await hisab.invoices.update('inv_8f3a91', { due_date: '2026-08-05' }); // drafts only
await hisab.invoices.finalize('inv_8f3a91');
await hisab.invoices.markAsSent('inv_8f3a91');
await hisab.invoices.markAsPaid('inv_8f3a91', { payment_method: 'bank_transfer' });
await hisab.invoices.void('inv_8f3a91', { reason: 'Duplicate billing' });

// exports
const pdf = await hisab.invoices.exportPdf('inv_8f3a91', { locale: 'fr' }); // ArrayBuffer
const xml = await hisab.invoices.exportXml('inv_8f3a91'); // UBL 2.1 string

Customers

Create and manage B2B / B2C customers, search by name or ICE, and archive without losing history.

TypeScript
// create a B2B customer (ICE required for B2B)
const customer = await hisab.customers.create({
  name: 'MERIT Sarl',
  type: 'b2b',
  ice: '001234567000089',
});

// read and update
const { data } = await hisab.customers.list({ type: 'b2b' });
await hisab.customers.update('cus_2b81fe', { email: 'finance@example.ma' });

// search helpers (built on list)
const matches = await hisab.customers.search('MERIT');
const byIce = await hisab.customers.findByIce('001234567000089');

// archiving keeps the invoice history
await hisab.customers.archive('cus_2b81fe');

Recurring invoices

Schedules that generate invoices on the frequency you define, with pause / resume and on-demand generation.

TypeScript
// a monthly schedule that finalizes its invoices automatically
const recurring = await hisab.recurringInvoices.create({
  customer_id: 'cus_2b81fe',
  frequency: 'monthly',
  start_date: '2026-07-01',
  auto_finalize: true,
  items: [{ description: 'Monthly retainer', quantity: 1, unit_price: 10400 }],
});

// control the schedule
await hisab.recurringInvoices.pause(recurring.id);
await hisab.recurringInvoices.resume(recurring.id, { next_run_date: '2026-08-01' });

// generate the next invoice on demand
const invoice = await hisab.recurringInvoices.generate(recurring.id);

// inspect past runs
const history = await hisab.recurringInvoices.getHistory(recurring.id);

Organization

Read your profile, subscription and API quotas; update legal identifiers and contact info.

TypeScript
// read your organization profile, subscription and API quotas
const org = await hisab.organization.get();
console.log(org.quotas.api_rate_limit_per_minute); // 120

// update legal identifiers and contact info
await hisab.organization.update({ phone: '+212 5 22 00 00 01' });

Webhooks

Verify the HMAC signature of incoming webhooks and parse events with type safety.

TypeScript
import { verifyWebhookSignature, parseWebhookEvent } from 'hisab-sdk';

// app/api/hisab-webhook/route.ts (Next.js)
export async function POST(req: Request) {
  const payload = await req.text();

  const valid = verifyWebhookSignature({
    payload,
    signature: req.headers.get('x-webhook-signature')!,
    timestamp: req.headers.get('x-webhook-timestamp')!,
    secret: process.env.HISAB_WEBHOOK_SECRET!,
  });
  if (!valid) return new Response('Invalid signature', { status: 401 });

  const event = parseWebhookEvent(payload);
  if (event.event === 'invoice.paid') {
    // mark the order as paid in your system
  }

  return new Response('ok');
}
Read the webhooks guide

Error handling

Every API error maps to a typed class carrying the HTTP status, the stable error code and field-level details.

TypeScript
import {
  ValidationError,
  AuthenticationError,
  NotFoundError,
  RateLimitError,
  HisabError,
} from 'hisab-sdk';

try {
  await hisab.invoices.finalize('inv_8f3a91');
} catch (err) {
  if (err instanceof ValidationError) {
    console.error(err.details); // field-level issues
  } else if (err instanceof RateLimitError) {
    console.error('Retry after', err.retryAfter, 'seconds');
  } else if (err instanceof NotFoundError) {
    // unknown invoice id
  } else if (err instanceof HisabError) {
    console.error(err.code, err.message);
  }
}

Pagination

Use page and per_page manually, or let listAll() iterate through every page for you.

TypeScript
// manual pagination
const page1 = await hisab.invoices.list({ page: 1, per_page: 50 });
console.log(page1.meta.pagination.total);

// auto-pagination - iterates every page for you
for await (const invoice of hisab.invoices.listAll({ status: 'paid' })) {
  console.log(invoice.invoice_number);
}

// or collect everything at once
const allPaid = await hisab.invoices.listAll({ status: 'paid' }).toArray();