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:
supportMode | What 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_direct | Opens 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:
- Staff ask in the admin console: a reason,
readorread_write, a duration (default 4 hours, at most 72) and optionally the escalation. You get the eventsupport.access_requested, and the company's admins see the request in thenotification-banner(approve or decline in place) and in thesupport-accesselement. - A company admin approves or declines, in the element or banner (an embed or headless token; if your
step_upprovider listssupport_access.approve, the admin confirms first). Or your backend decides for them withplatform.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. - The grant is
activeuntilexpiresAt(support.access_granted). The company or you can end it any time withplatform.support.grants.revoke(grantId)(support.access_revoked); expiry issupport.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:
read | read_write | |
|---|---|---|
| View the company's books, filings and settings | yes | yes |
| 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 access | never (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.