FinBaze for Platforms

Concepts

Policies#

A policy is a versioned setting for all your companies, with an override per company. Kinds: category_mapping (including MCC codes), chart_template, booking_rules, filing_policy, roles_mapping, company_defaults (including optional modules), quotas, messaging and documents.

You write a draft, FinBaze validates it against the kind's schema (platform.policies.schemas()), and activating it makes it live and archives the previous version. A company override applies on top of the platform policy; effective shows the result.

const draft = await finbaze.platform.policies.createDraft("quotas", { aiRunsPerMonth: 200 });
await finbaze.platform.policies.activate(draft.id);

await finbaze.platform.policies.overrides.set(companyId, "quotas", { aiRunsPerMonth: 20 });
const effective = await finbaze.platform.policies.effective("quotas", companyId);

Sandbox to production#

Configure in the sandbox, then promote with one action. In the sandbox bundle.export signs a bundle of the active policies; in production you preview it (a diff per kind plus warnings) and confirm the import, which activates every kind in one transaction.

const bundleId = await sandbox.platform.policies.bundle.export(); // all kinds, or pass a list
const preview = await live.platform.policies.bundle.preview(bundleId);
if (preview.warnings.length === 0) await live.platform.policies.bundle.confirm(preview.importId);

Filing policy produces tax.deadline_upcoming messages and can require roles to prepare and approve a filing. quota.reached is sent once a month when a quota is used up, and policy.activated when a version goes live.

Extensions#

Custom actions add buttons next to FinBaze's own on a booking, an invoice or a transaction. A click either calls your embed callback or sends custom_action.invoked to your endpoints. Slots are named places on a screen where you put items. Link templates turn a FinBaze object into a link in your own app ("Open shipment in TMS"), and linkTemplates.resolve returns the resolved links; the host of every link must be one of your allowed origins.

const ext = finbaze.platform.extensions;
await ext.linkTemplates.upsert({
  resourceType: "sales_invoice",
  urlTemplate: "https://tms.example.com/shipments/{externalId}",
  label: { en: "Open shipment", nl: "Open zending" },
});
await ext.customActions.upsert({
  key: "open_tms",
  label: { en: "Open in TMS" },
  placements: ["sales_invoice"],
  contextType: "sales_invoice",
});

Custom fields add your own typed fields to invoices, transactions, relations and projects (feature extensions.custom_fields). They show in the embedded views, can be included in events (custom_fields) and on documents, and are written with customFields.setValues; only the keys you pass change.

Field control hides, locks or presets a field of a FinBaze view, for all your companies or one. Fields the law requires on a document cannot be controlled. A write to a locked field fails with FIELD_LOCKED.

await ext.customFields.define({ entityType: "sales_invoice", key: "shipment", label: { en: "Shipment" }, type: "text" });
await ext.fieldControl.set({ view: "invoice", field: "reference", mode: "locked" });