@thredfi/accounting
v0.10.0
Published
Embeddable accounting widget for integrating Thredfi accounting features into your application
Downloads
607
Readme
Embeddable accounting widget by Thredfi
📦 Installation
npm install @thredfi/accounting🚀 Quick Start
ES Module (npm/bundler)
For Registered Businesses
import {
mountThredfi,
unmountThredfi,
setThredfiLanguage,
type TokenFetcher,
type TokenResponse,
} from "@thredfi/accounting";
mountThredfi({
// CSS selector for the container element
thredfiSelector: "#thredfi-widget",
// Function to fetch authentication token from your backend
getToken: async () => {
const response = await fetch("https://your-api.com/thredfi-token", {
headers: {
Authorization: "Bearer your-auth-token",
},
});
return await response.json();
},
// Your business UUID in the Thredfi system
businessId: "964f4325-3efb-400d-a1bd-8b1f29e828cf",
lang: "en",
environment: "production", // "development" | "staging" | "sandbox" | "production" | "local"
// Theme customization (optional)
theme: {
navigationBackgroundColor: "#f9f9f9",
cardsBackgroundColor: "#ffffff",
textColor: "#111827",
textSecondaryColor: "#6b7280",
activeColor: "#871f91",
borderColor: "#dcdcdc",
borderSecondaryColor: "#e5e7eb",
},
// Base path for routing within the widget
basePath: "/accounting",
// Hide the header navigation menu (optional)
hideMenu: false,
});For Unregistered Businesses
If the business is not yet registered in Thredfi, you can mount the widget with registration details. The user will see a sales/onboarding page instead of the full accounting interface:
import { mountThredfi, type RegistrationDetails } from "@thredfi/accounting";
mountThredfi({
thredfiSelector: "#thredfi-widget",
registrationDetails: {
partnerId: "partner-uuid",
businessName: "Acme Corporation",
personName: "John Doe",
emailId: "[email protected]",
phone: "+1234567890", // Optional
countryCode: "US",
},
lang: "en",
environment: "production",
basePath: "/my-app/sales", // Optional: Base path for routing
});CDN Usage (UMD)
Use directly in the browser without a bundler:
For Registered Businesses
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>My App with Thredfi</title>
</head>
<body>
<!-- Container for the widget -->
<div id="thredfi-widget"></div>
<!-- Load from CDN -->
<script src="https://unpkg.com/@thredfi/accounting@latest/dist/index.umd.js"></script>
<script>
// Access via global ThredfiAccounting object
ThredfiAccounting.mountThredfi({
thredfiSelector: "#thredfi-widget",
getToken: async () => {
const response = await fetch("https://your-api.com/thredfi-token", {
headers: {
Authorization: "Bearer your-auth-token",
},
});
return await response.json();
},
businessId: "964f4325-3efb-400d-a1bd-8b1f29e828cf",
environment: "production",
});
</script>
</body>
</html>For Unregistered Businesses
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Thredfi Sales</title>
</head>
<body>
<div id="thredfi-widget"></div>
<script src="https://unpkg.com/@thredfi/accounting@latest/dist/index.umd.js"></script>
<script>
ThredfiAccounting.mountThredfi({
thredfiSelector: "#thredfi-widget",
registrationDetails: {
partnerId: "partner-uuid",
businessName: "Acme Corporation",
personName: "John Doe",
emailId: "[email protected]",
countryCode: "US",
},
environment: "production",
basePath: "/sales", // Optional: Base path for routing
});
</script>
</body>
</html>📖 API Reference
mountThredfi(options)
Mounts the Thredfi accounting widget in the specified container.
The widget supports two modes:
- Registered businesses: Full accounting interface with authentication
- Unregistered businesses: Sales/onboarding page with registration details
Options
// Shared configuration for both modes
interface BaseMountOptions {
thredfiSelector: string; // Required: CSS selector for container
lang?: string; // Optional: Language code (default: "en")
environment?: "development" | "staging" | "sandbox" | "production" | "local"; // Optional: Backend environment (default: "sandbox")
basePath?: string; // Optional: Base path for routing (default: "")
theme?: ThemeConfig; // Optional: Color overrides for theming
hideMenu?: boolean; // Optional: Hide header navigation (default: false)
}
// Case A: Registered businesses
interface RegisteredOptions extends BaseMountOptions {
businessId: string; // Required: Business UUID in Thredfi system
getToken: () => Promise<{
// Required: Token fetcher function
access_token: string;
expires_in: number;
}>;
registrationDetails?: never; // Cannot be used with businessId
}
// Case B: Unregistered businesses
interface UnregisteredOptions extends BaseMountOptions {
registrationDetails: RegistrationDetails; // Required: Registration info
businessId?: never; // Cannot be used with registrationDetails
getToken?: never; // Not needed for unregistered businesses
}
// Registration details for businesses not yet in Thredfi
interface RegistrationDetails {
partnerId: string; // Required: Partner UUID (must be valid UUID format)
businessName: string; // Required: Business/company name (non-empty string)
personName: string; // Required: Contact person name (non-empty string)
emailId: string; // Required: Contact email (must be valid email format)
phone?: string; // Optional: Contact phone number (non-empty string if provided)
countryCode: string; // Required: ISO 3166-1 alpha-2 country code (e.g., "US", "GB")
}
// Final exported type (discriminated union)
type ThredfiMountOptions = RegisteredOptions | UnregisteredOptions;Validation Rules for RegistrationDetails
When using registrationDetails, the following validations are automatically performed:
| Field | Validation Rules | Example |
| -------------- | ----------------------------------- | ---------------------------------------- |
| partnerId | Must be a valid UUID format | "550e8400-e29b-41d4-a716-446655440000" |
| businessName | Non-empty string | "Acme Corporation" |
| personName | Non-empty string | "John Doe" |
| emailId | Valid email format | "[email protected]" |
| phone | Non-empty string (if provided) | "+1234567890" |
| countryCode | ISO 3166-1 alpha-2 code (2 letters) | "US", "GB", "DE" |
Validation Errors:
If validation fails, mountThredfi() will throw a descriptive error:
// Invalid email
throw new Error(
"[Thredfi] registrationDetails.emailId has invalid email format",
);
// Invalid UUID
throw new Error("[Thredfi] registrationDetails.partnerId must be a valid UUID");
// Invalid country code
throw new Error(
"[Thredfi] registrationDetails.countryCode must be a valid ISO 3166-1 alpha-2 country code (e.g., 'US', 'GB')",
);
// Missing required field
throw new Error(
"[Thredfi] registrationDetails.businessName is required and must be a non-empty string",
);Theme Configuration
interface ThemeConfig {
navigationBackgroundColor?: string; // Background color for header/navigation
cardsBackgroundColor?: string; // Background color for cards and panels
textColor?: string; // Main text color
textSecondaryColor?: string; // Secondary/muted text color
activeColor?: string; // Active/highlight/profit color
borderColor?: string; // Border color for elements
borderSecondaryColor?: string; // Light/secondary border color
}Usage Examples
Registered Business:
mountThredfi({
thredfiSelector: "#app",
businessId: "uuid-here",
getToken: async () => ({ access_token: "token", expires_in: 3600 }),
});Unregistered Business:
mountThredfi({
thredfiSelector: "#app",
registrationDetails: {
partnerId: "partner-id",
businessName: "Acme Corp",
personName: "John Doe",
emailId: "[email protected]",
countryCode: "US",
},
});unmountThredfi()
Unmounts the currently mounted widget and cleans up resources.
unmountThredfi();When to use:
- Cleaning up before remounting with different options
- Component unmount in React/Vue/Angular
- Page navigation cleanup
setThredfiLanguage(lang)
Changes the language of the mounted widget at runtime.
setThredfiLanguage("de"); // Switch to German
setThredfiLanguage("es"); // Switch to SpanishNote: The widget must be mounted before calling this function.
🌍 Supported Languages
| Code | Language |
| ---- | ---------------- |
| en | English |
| de | German |
| es | Spanish |
| fr | French |
| it | Italian |
| nl | Dutch |
| no | Norwegian |
🌐 Environment Configuration
The environment option controls which backend API the widget connects to:
| Environment | Backend URL | Use Case |
| ------------ | ----------------------------------- | --------------- |
| sandbox | https://sandbox-backend.thredfi.com | Testing/Sandbox |
| production | https://backend.thredfi.com | Production |
mountThredfi({
// ... other options
environment: "production", // Default is "sandbox"
});🎛️ Hide Header Menu
You can hide the header navigation menu to show only the content:
mountThredfi({
// ... other options
hideMenu: true, // Hide the header menu
});This is useful when:
- Embedding specific views directly
- Implementing your own custom navigation (see Custom Navigation Menu)
- Integrating with an existing app layout
The SDK listens to route changes and renders the matching view automatically.
🎨 Theming
Customize the widget appearance with simple color overrides:
mountThredfi({
// ... other options
theme: {
navigationBackgroundColor: "#f9f9f9", // Background color for header/navigation
cardsBackgroundColor: "#ffffff", // Background color for cards and panels
textColor: "#111827", // Main text color
textSecondaryColor: "#6b7280", // Secondary/muted text color
activeColor: "#871f91", // Active/highlight/profit color
borderColor: "#dcdcdc", // Border color for elements
borderSecondaryColor: "#e5e7eb", // Light/secondary border color
},
});Available theme properties:
| Property | Description | Default |
| --------------------------- | -------------------------------------- | --------- |
| navigationBackgroundColor | Background color for header/navigation | #f9f9f9 |
| cardsBackgroundColor | Background color for cards and panels | #ffffff |
| textColor | Main text color throughout the widget | #111827 |
| textSecondaryColor | Secondary/muted text color | #6b7280 |
| activeColor | Active/highlight/profit color | #871f91 |
| borderColor | Border color for elements | #dcdcdc |
| borderSecondaryColor | Light/secondary border color | #e5e7eb |
🔐 Authentication
The widget requires a getToken function to fetch authentication tokens. This gives you full control over how tokens are fetched, including adding custom headers and authentication. Use Thredfi's API key to create short-lived tokens that can be used in the frontend.
Example of a Token Fetcher Function:
import { mountThredfi, type TokenFetcher } from "@thredfi/accounting";
const getToken: TokenFetcher = async () => {
const response = await fetch("https://your-api.com/thredfi-token", {
headers: {
Authorization: "Bearer your-auth-token", // Add your own auth
"X-Custom-Header": "custom-value", // any custom headers
},
});
const data = await response.json();
return {
access_token: data.access_token,
expires_in: data.expires_in,
};
};
mountThredfi({
// ... other options
getToken, // Your custom token fetcher
});Token Response Format
Your getToken function must return an object with:
access_token(string) - The JWT access tokenexpires_in(number) - Token expiration time in seconds
Example response:
{
access_token: "eyJhbGciOiJIUzI1NiIs...",
expires_in: 3600
}Automatic Token Management
The widget automatically:
- Calls
getTokenbefore making API requests - Refreshes expired tokens (60 seconds before expiration)
- Calls
getTokenwhen a 401 error is received - Retries failed requests with new tokens
🧭 Custom Navigation Menu
When embedding the Thredfi widget, you can hide the built-in header menu and implement your own custom navigation (e.g., a vertical sidebar). The SDK automatically renders the correct view based on the current URL path.
Available Routes
| Route | Description |
| ---------------------------------- | --------------------------------- |
| /insights | Dashboard with financial overview |
| /tasks | Tasks and action items |
| /bank-transactions | Bank transactions management |
| /reports | Financial reports |
| /general-ledger | General ledger (redirects to journal-entries) |
| /general-ledger/journal-entries | Journal entries list |
| /general-ledger/chart-of-accounts| Chart of accounts |
| /accounts-receivable | AR section (redirects to invoices)|
| /accounts-receivable/invoices | Customer invoices |
| /accounts-receivable/credit-notes| Customer credit notes |
| /accounts-payable | AP section (redirects to bills) |
| /accounts-payable/bills | Vendor bills |
| /accounts-payable/credits | Vendor credits |
How It Works
- Hide the SDK menu: Set
hideMenu: trueto remove the built-in header navigation - Use your router: Navigate using your app's router (React Router, Next.js, etc.)
- SDK responds to URL: The SDK listens to route changes and renders the matching view
- Set
basePath: If your app mounts at a sub-path (e.g.,/accounting), setbasePathaccordingly
With Sub-Path Example
// If your app is mounted at /accounting
mountThredfi({
thredfiSelector: "#thredfi-widget",
businessId: "your-business-id",
getToken: yourTokenFetcher,
basePath: "/accounting", // SDK routes become /accounting/insights, etc.
hideMenu: true,
});
// Your navigation would use full paths
const navItems = [
{ label: "Insights", path: "/accounting/insights" },
{ label: "Tasks", path: "/accounting/tasks" },
// ...
];📘 TypeScript Support
The package includes full TypeScript definitions. Import types for better development experience:
import {
type ThredfiMountOptions,
type RegistrationDetails,
type TokenFetcher,
type TokenResponse,
type ThredfiLanguage,
} from "@thredfi/accounting";