FinBaze for Platforms

Concepts

Two things live here: how a support request from one of your users is handled (you first, or FinBaze directly), and the rule that FinBaze staff can open one of your companies only with the company's consent.

Who answers your users#

The embedded contact-support element is the "Contact support" button. What it does depends on supportMode, which you set per platform in the portal (Support) or with platform.support.settings.update:

supportModeWhat the button does
partner_first (default)Tells your page (support.requested event) and your backend (webhook support.requested). You answer, and escalate to FinBaze through the API when you need to. If your page has no handler and you set a supportUrl, the SDK opens it.
finbaze_directOpens FinBaze's form. The case becomes an escalation (source: user) for FinBaze support, with the request ids attached.

The event data is { companyId, screen, requestIds, componentVersion }: requestIds are the X-Request-Id values of the last (up to five) failed calls of that page, so you or FinBaze can find them in the logs and the audit log. Every API response carries an X-Request-Id header (send your own, 8 to 64 characters of A-Z a-z 0-9 . _ -, and it is kept), embed errors carry it as requestId, and the audit log stores it.

const instance = await loadFinBaze(publishableKey, { fetchClientSecret });
const help = instance.create("contact-support", { screen: "vat-return" });
help.on("support.requested", ({ companyId, requestIds }) => openMyHelpWidget(companyId, requestIds));
help.mount("#help");

Settings: supportMode, supportUrl (https), supportEmail and supportEscalationEnabled (default true; false makes createSupportEscalation fail with SUPPORT_ESCALATION_DISABLED).

Escalating to FinBaze#

Level 2 is FinBaze. With your server key (scope support:write):

const escalation = await finbaze.platform.support.escalations.create({
  companyId, subject: "VAT draft starts a quarter late",
  description: "Since this morning ...", severity: "high",
  requestIds: ["7b0c2f1e-..."], screen: "vat-return",
});
await finbaze.platform.support.escalations.comment(escalation.id, "Request 7b0c2f1e is the first failing one.");
const open = await finbaze.platform.support.escalations.list({ status: ["open", "in_progress"] });

FinBaze support is mailed (there is no helpdesk integration yet) and works the case in an admin list. Statuses: open, in_progress, waiting_on_platform, resolved, closed. Your comment on a case that waits for you or is resolved reopens it. Events: support.escalation.created and support.escalation.updated (data.object.change is status, severity or comment). Which member of staff handles it is not shared.

Consented view-as#

FinBaze staff used to open any company. For a company on your platform they now need a support access grant:

  1. Staff ask in the admin console: a reason, read or read_write, a duration (default 4 hours, at most 72) and optionally the escalation. You get the event support.access_requested, and the company's admins see the request in the notification-banner (approve or decline in place) and in the support-access element.
  2. A company admin approves or declines, in the element or banner (an embed or headless token; if your step_up provider lists support_access.approve, the admin confirms first). Or your backend decides for them with platform.support.grants.decide(grantId, { approve: true, attestation: "…" }); a server token must say how it obtained the consent (attestation, at least 10 characters), which is recorded. A token your backend minted for a user cannot consent.
  3. The grant is active until expiresAt (support.access_granted). The company or you can end it any time with platform.support.grants.revoke(grantId) (support.access_revoked); expiry is support.access_expired. Expiry and revocation take effect on the next request.
const grants = await finbaze.platform.support.grants.list(companyId);          // requested and active
await finbaze.platform.support.grants.decide(grants[0].id, { approve: true, attestation: "Customer agreed on ticket #4411" });
await finbaze.platform.support.grants.revoke(grants[0].id);

What a grant allows:

readread_write
View the company's books, filings and settingsyesyes
Change data (invoices, relations, settings)no (SUPPORT_GRANT_READ_ONLY)yes
Submit filings, give or withdraw filing consent, decide firm connections, move the company, decide on support accessnever (SUPPORT_GRANT_DENIED_OPERATION)never

Without a grant, staff cannot open the company at all (SUPPORT_GRANT_REQUIRED); direct FinBaze companies are not affected. Everything staff do under a grant is audited as actor kind support with the grant id and shows in platform.audit.list (reads too). The platform and the company never see a staff member's name, only "FinBaze support" and the reason.

Break-glass#

For a legal order or a security incident FinBaze can open a company without consent: one FinBaze admin requests it with a written reason and a second admin approves. It is read only, lasts two hours at most and you receive support.break_glass the moment it starts. Staff cannot approve their own request.

Errors and events#

Errors: SUPPORT_GRANT_REQUIRED, SUPPORT_GRANT_READ_ONLY, SUPPORT_GRANT_DENIED_OPERATION, SUPPORT_GRANT_NOT_PENDING, SUPPORT_GRANT_NOT_ACTIVE, SUPPORT_ATTESTATION_REQUIRED, SUPPORT_COMPANY_ADMIN_REQUIRED, SUPPORT_ESCALATION_DISABLED.

Events: support.requested, support.escalation.created, support.escalation.updated, support.access_requested, support.access_granted, support.access_revoked, support.access_expired, support.break_glass. Their data.object JSON Schemas are in the event catalogue.

Scopes: support:read and support:write. The support-access element has the features decide and revoke; notification-banner has supportApproval. Each can be switched off per session, in which case that control is not shown.