Provider Setup
React UI components usually need:
- SpaceInvoicesProvider — Initializes the modular SDK runtime
- EntitiesProvider — Optional active-entity state for multi-entity apps
CreateInvoiceScreen is self-contained for standalone consumers: it renders
the Save and Save as Draft actions when no host footer provider exists. If the
host already has a FormFooterProvider, the screen registers with that
provider and the host should render its existing StickyFormFooter once.
CreateInvoiceForm by itself should either be rendered under that provider or
pass its onFooterStateChange state to a host-owned footer.
Full Setup
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { EntitiesProvider } from "./providers/entities-provider";
import { SpaceInvoicesProvider } from "./providers/space-invoices-provider";
const queryClient = new QueryClient();
const activeAccountId = "acc_123"; // Required for multi-account user-token flows
export function App() {
return (
<QueryClientProvider client={queryClient}>
<SpaceInvoicesProvider
accessToken={() => localStorage.getItem("access_token") ?? ""}
accountId={activeAccountId}
basePath="https://eu.spaceinvoices.com"
>
<EntitiesProvider>
{/* Your app components */}
<Router />
</EntitiesProvider>
</SpaceInvoicesProvider>
</QueryClientProvider>
);
}SpaceInvoicesProvider
The SpaceInvoicesProvider initializes the Space Invoices runtime and makes authenticated SDK calls work inside copied components.
For multi-account browser apps using a user token, pass accountId explicitly. API-key, embed, and single-account flows can leave it unset.
Props
| Prop | Type | Description |
|---|---|---|
basePath | string | API base URL |
accessToken | string | () => string | Promise<string> | Token value or async token resolver |
accountId | string | null | Optional active account ID |
clientName | string | Optional client header override |
onUnauthorized | (response: Response) => void | Optional auth failure handler |
Getting the Token
How you get the token depends on your auth setup:
// From localStorage
const fromLocalStorage = () => localStorage.getItem("si_token");
// From a cookie
const _fromCookie = () => document.cookie.match(/token=([^;]+)/)?.[1] ?? null;
// From an auth library (e.g., NextAuth)
const _fromSession = (session) => session?.accessToken ?? null;
// For multi-account user-token flows, also pass the active account explicitly.
const activeAccountId = "acc_123";
// Usage in SpaceInvoicesProvider:
<SpaceInvoicesProvider
basePath="https://eu.spaceinvoices.com"
accessToken={fromLocalStorage}
accountId={activeAccountId}
>
{/* or getAccessToken={fromCookie} */}
{/* or accessToken={() => fromSession(session) ?? ""} */}
</SpaceInvoicesProvider>;Multi-account apps
If your host app lets a user switch between multiple accounts, pass the currently selected account ID into SpaceInvoicesProvider. The React UI package does not infer account context from browser cookies.
EntitiesProvider
The EntitiesProvider manages entity selection for multi-entity apps. If your host app already knows the entity, prefer explicit entityId props and skip this provider.
Hosts that need branded loading UI can pass a fallbackLoading React node; when omitted, the provider uses its generic accessible loading overlay.
Using Active Entity
import { useEntities } from "@/providers/entities-provider";
function _InvoicesPage() {
const { activeEntity, isLoading } = useEntities();
if (isLoading) return <Spinner />;
if (!activeEntity) return <NoEntitySelected />;
return <InvoiceListTable entityId={activeEntity.id} onRowClick={(inv) => navigate(`/invoices/${inv.id}`)} />;
}Entity Switching
import { useEntities } from "@/providers/entities-provider";
function _EntitySelector() {
const { entities, activeEntity, setActiveEntity } = useEntities();
return (
<Select
value={activeEntity?.id}
onValueChange={(id) => {
const entity = entities.find((e) => e.id === id);
if (entity) setActiveEntity(entity);
}}
>
{entities.map((entity) => (
<SelectItem key={entity.id} value={entity.id}>
{entity.name}
</SelectItem>
))}
</Select>
);
}Accessing the SDK Directly
Components use the SDK internally, but for custom code prefer direct modular SDK imports instead of a provider hook:
import { invoices } from "@spaceinvoices/js-sdk/sdk";
function _CustomComponent() {
const handleCustomAction = async () => {
// Prefer direct modular SDK imports for custom operations
const result = await invoices.renderPdf(invoiceId);
downloadBlob(result, "invoice.pdf");
};
return <Button onClick={handleCustomAction}>Download PDF</Button>;
}Next Steps
- Components — Available components
- Customization — Modify components