SDK
Access Fireberry context and data from your embedded applications
Fireberry SDK
The Fireberry SDK (@fireberry/sdk) enables your app to communicate with the Fireberry platform. Use it to access information about the current user and record, and to perform data operations.
Resources:
Installation
npm install @fireberry/sdkQuick Start
import FireberryClientSDK from "@fireberry/sdk/client";
// 1. Create the client
const client = new FireberryClientSDK();
// 2. Initialize (required before using context or API)
await client.initializeContext();
// 3. Use context and API
const { user, record } = client.context;
const { fullName, license } = user;
const results = await client.api.query(1, {
fields: "accountid,accountname",
query: 'status = "active"',
});How It Works
Your app runs in an iframe inside Fireberry. The SDK handles all communication with the parent window:
sequenceDiagram
participant App as Your App (iframe)
participant SDK as Fireberry SDK
participant FB as Fireberry Platform
App->>SDK: initializeContext()
SDK->>FB: Request context
FB-->>SDK: User + Record info
SDK-->>App: Context ready
App->>SDK: api.query(...)
SDK->>FB: Query API request
FB-->>SDK: Data response
SDK-->>App: Results
Context
Context provides information about who's using your app and what they're looking at.
Accessing Context
await client.initializeContext();
const { user, record } = client.context;
// User info (always available)
console.log(user.id); // User's unique ID
console.log(user.fullName); // User's display name
console.log(user.organizationId); // User's organization ID
console.log(user.license); // License details (or null)
// Record info (only in Record components)
console.log(record.id); // Current record ID
console.log(record.type); // Object type number
console.log(record.storage); // File storage scoped to this recordContext by Component Type
| Context | Record Component | Side Menu | Global Menu |
|---|---|---|---|
user.id | ✓ | ✓ | ✓ |
user.fullName | ✓ | ✓ | ✓ |
user.organizationId | ✓ | ✓ | ✓ |
user.license | ✓ | ✓ | ✓ |
user.permissions | ✓ | ✓ | ✓ |
record.id | ✓ | — | — |
record.type | ✓ | — | — |
record.storage | ✓ | — | — |
NoteRecord context is only available in Record components. For Side Menu and Global Menu components,
recordwill be empty.
License (user.license)
user.license provides information about the organization's Fireberry license. It is available in all component types (Record, Side Menu, Global Menu). When license information is not available, user.license is null.
Structure:
| Field | Type | Description |
|---|---|---|
licenseLevel | number | License tier/level |
invoiceName | string | Name on the license invoice |
subscription | object | Optional. Present when the org has a subscription |
subscription (when present):
| Field | Type | Description |
|---|---|---|
seats | number | Number of seats |
billingCyclePlan | number | 1 = Annual, 2 = Monthly |
status | number | Subscription status (see below) |
endDate | Date | Subscription end date |
Subscription status values: 1 = Active, 2 = Inactive, 3 = ChargeError, 4 = BlockedPayment, 5 = Trial, 6 = TrialExpired.
Permissions
After initialization, context.user.permissions contains the current user's role-based permissions. Use these to adapt your app's behavior to what the user is allowed to do in the organization — for example, hiding a "Create" button when the user lacks create access, or gating a feature behind a permission check.
Permissions are split into two categories: object permissions (CRUD access per CRM object) and feature permissions (access to platform capabilities).
Object Permissions
Each CRM object type carries four boolean flags indicating what the current user can do:
import FireberryClientSDK, { OBJECTS } from "@fireberry/sdk/client";
const client = new FireberryClientSDK();
await client.initializeContext();
const { permissions } = client.context.user;
const accountPerms = permissions.objects[OBJECTS.account];
accountPerms.create; // boolean
accountPerms.read; // boolean
accountPerms.update; // boolean
accountPerms.delete; // booleanObjectPermission:
| Property | Type | Description |
|---|---|---|
create | boolean | Whether the user can create records |
read | boolean | Whether the user can view records |
update | boolean | Whether the user can edit records |
delete | boolean | Whether the user can delete records |
Use the OBJECTS constant for readable, type-safe lookups. For custom object types (not included in OBJECTS), use the numeric ID directly with optional chaining — or register them via declaration merging for full type safety:
// Built-in object — type-safe, no optional chaining needed
permissions.objects[OBJECTS.contact].read;
// Custom object by numeric ID — may be undefined
permissions.objects[1001]?.read;The OBJECTS constant includes all built-in CRM entities (account, contact, opportunity, task, order, product, etc.). Import it to see the full list in your editor's autocomplete.
Feature Permissions
Feature permissions control access to platform capabilities. Each feature has a single allowed boolean:
const { permissions } = client.context.user;
if (permissions.features.billing.allowed) {
// user has access to billing features
}
if (permissions.features.settings.allowed) {
// user can access org settings
}FeaturePermission:
| Property | Type | Description |
|---|---|---|
allowed | boolean | Whether the user has access to the feature |
Features are accessed by their string name (e.g. "billing", "settings", "webservices"). The available features depend on the organization's plan and configuration.
Permissions Example
Guard actions and conditionally render UI based on the user's permissions:
import FireberryClientSDK, { OBJECTS } from "@fireberry/sdk/client";
const client = new FireberryClientSDK();
await client.initializeContext();
const { permissions } = client.context.user;
const objectType = client.context.record.type ?? OBJECTS.account;
// Guard an update operation
if (permissions.objects[objectType]?.update) {
await client.api.update(objectType, recordId, { status: "active" });
} else {
console.warn("User does not have update access to this object type");
}
// Check a feature before offering it in the UI
const canExport = permissions.features.exportexel?.allowed ?? false;
NotePermissions are read-only. They reflect the logged-in user's role as configured by the organization admin and cannot be changed from the SDK.
API Methods
The SDK provides methods for working with Fireberry data and discovering object schemas:
| Method | Description |
|---|---|
api.query() | Retrieve records |
api.create() | Create a new record |
api.update() | Update an existing record |
api.delete() | Delete a record |
api.metadata.getObjects() | List all CRM object types |
api.metadata.getFields() | List field names for an object type |
api.metadata.getField() | Get metadata for a specific field |
query
Retrieve records based on criteria.
const results = await client.api.query(objectType, {
fields: "accountid,accountname,status,createdon",
query: 'status = "active"',
page_size: 20, // optional
page_number: 1, // optional
});Parameters:
| Parameter | Type | Description |
|---|---|---|
objectType | string | number | The object type to query |
fields | string | Comma-separated list of fields to return |
query | string | Filter expression |
page_size | number | Records per page (optional) |
page_number | number | Page number, 1-indexed (optional) |
Query syntax:
| Operator | Example |
|---|---|
= | status = "active" |
!= | status != "closed" |
AND | status = "active" AND priority = "high" |
OR | status = "open" OR status = "pending" |
create
Create a new record.
const result = await client.api.create(objectType, {
name: "New Project",
status: "active",
priority: "high",
});
if (result.success) {
console.log("Created:", result.data.id);
}update
Update an existing record.
const result = await client.api.update(objectType, recordId, {
status: "completed",
});
if (result.success) {
console.log("Updated successfully");
}delete
Delete a record.
const result = await client.api.delete(objectType, recordId);
if (result.success) {
console.log("Deleted");
}metadata.getObjects
List all CRM object types available to the current user.
const objects = await client.api.metadata.getObjects();
// e.g. [{ type: 1, name: "Account", pluralName: "Accounts" }, ...]Returns: Promise<ObjectMeta[]> — an array of object type metadata.
ObjectMeta:
| Property | Type | Description |
|---|---|---|
type | number | Numeric object type code |
name | string | Singular display name (e.g. "Account") |
pluralName | string | Plural display name (e.g. "Accounts") |
metadata.getFields
List all field names available on an object type.
const fieldNames = await client.api.metadata.getFields(objectType);
// e.g. ["accountid", "accountname", "status", "email", "telephone1"]Parameters:
| Parameter | Type | Description |
|---|---|---|
objectType | string | number | The object type to inspect |
Returns: Promise<string[]> — an array of field names.
metadata.getField
Get detailed metadata for a single field, including its display label, data type, and whether it is read-only.
const field = await client.api.metadata.getField(objectType, "status");
console.log(field.label); // "Status"
console.log(field.type); // "picklist"
console.log(field.readonly); // falseParameters:
| Parameter | Type | Description |
|---|---|---|
objectType | string | number | The object type to inspect |
fieldName | string | The field to retrieve |
Returns: Promise<FieldMeta> — metadata for the requested field.
FieldMeta
FieldMeta is a discriminated union — the type property determines which additional fields are present. TypeScript narrows the type automatically when you check type.
Base properties (always present):
| Property | Type | Description |
|---|---|---|
name | string | System name of the field |
label | string | Display label |
type | FieldType | Data type (see table below) |
readonly | boolean | Whether the field can be written to |
Additional properties by type:
type value | Extra property | Description |
|---|---|---|
'lookUp' | relatedObjectType: number | The object type this lookup points to |
'picklist' | options: PicklistOption[] | The available options for the picklist |
| All others | — | No additional properties |
PicklistOption:
| Property | Type | Description |
|---|---|---|
value | number | Numeric value stored in the record |
textValue | string | Display text for this option |
order | number | Sort order |
FieldType values:
date · dateTime · emailAddress · lookUp · number · picklist · richText · text · textArea · url · telephone · formula · summary
Runtime constantThe
FIELD_TYPESarray is exported from@fireberry/sdk/clientso you can iterate over the possible values at runtime:import { FIELD_TYPES } from "@fireberry/sdk/client"; // FIELD_TYPES = ['date', 'dateTime', 'emailAddress', ...] as const
Example — inspecting fields and narrowing by type:
const fields = await client.api.metadata.getFields(objectType);
for (const name of fields) {
const field = await client.api.metadata.getField(objectType, name);
if (field.readonly) {
continue; // skip computed / system fields
}
switch (field.type) {
case "picklist":
// TypeScript knows `field.options` exists here
console.log(
`${field.label} choices:`,
field.options.map((o) => o.textValue),
);
break;
case "lookUp":
// TypeScript knows `field.relatedObjectType` exists here
console.log(`${field.label} → object type ${field.relatedObjectType}`);
break;
default:
console.log(`${field.label} (${field.type})`);
}
}Response Format
All API methods return the same structure:
interface ResponseData {
success: boolean;
data: any;
error?: {
status: number;
statusText: string;
data: { Message?: string };
};
requestId: string;
}Handling responses:
const result = await client.api.query(1, {
fields: "accountid,accountname",
query: 'status = "active"',
});
if (result.success) {
console.log("Data:", result.data);
} else {
console.error("Error:", result.error?.data.Message);
}Settings API
The Settings API provides persistent storage scoped to your app. Use it to save configuration, user preferences, or any state that should survive page reloads. Because all components within the same app share a single settings store, it also serves as the primary mechanism for cross-component communication.
| Method | Description |
|---|---|
app.settings.get() | Read the current settings value |
app.settings.set() | Write a new settings value |
app.settings.get
Read the stored settings for your app.
const settings = await client.app.settings.get();app.settings.set
Replace the stored settings with a new value. Returns the stored value after writing.
await client.app.settings.set({ theme: "dark", language: "en" });
Important: Full replace, not merge
app.settings.set()replaces the entire stored value — it does not merge or patch. If you only want to update one key, read the current settings first and spread them:// ❌ WRONG — overwrites everything; "language" is lost await client.app.settings.set({ theme: "light" }); // ✅ CORRECT — merge with existing settings, then write const current = await client.app.settings.get(); await client.app.settings.set({ ...current, theme: "light" });
How Settings Scoping Works
Settings are per-app, per-organization:
- All components in the same app read and write the same settings store.
- Different apps cannot access each other's settings.
- Settings are scoped to the organization, not to individual users — every user in the org sees the same data.
- Settings persist across page reloads and browser sessions.
flowchart TB
subgraph App["Your App"]
S[(Settings Store)]
end
R[Record Component] -->|read / write| S
G[Global Menu Component] -->|read / write| S
SM[Side Menu Component] -->|read / write| S
When your app has multiple components, coordinate which keys each component owns. For example, a Record component might own focusedAccount, while a Side Menu component owns taskSummary. Each component reads keys written by others, but only writes to its own.
NoteComponents do not receive real-time updates when another component changes settings. To see changes made by a sibling component, call
app.settings.get()again — for example, in response to a user action or a manual "Refresh" button.
Storage
The Storage API lets you upload, list, and manage files. Storage is available in two scopes:
| Scope | Access | Use case |
|---|---|---|
| App | client.app.storage | Files for your app (any component; list, upload, get, delete). |
| Record | client.context.record.storage | Files attached to the current record (Record components only; list and upload). |
App storage is available in all component types. Record storage is only available after initializeContext() in Record components and is scoped to the current record.
app.storage
App-level file storage. Available in Record, Side Menu, and Global Menu components.
| Method | Description |
|---|---|
app.storage.uploadFile() | Upload a file; returns url and id. |
app.storage.getFile() | Get a file by ID (returns a File). |
app.storage.deleteFile() | Delete a file by ID. |
app.storage.getFiles() | List files with pagination. |
app.storage.uploadFile
Upload a file to app storage.
const { url, id } = await client.app.storage.uploadFile(file);Parameters: file — a File (e.g. from <input type="file">).
Returns: Promise<{ url: string; id: string }>.
app.storage.getFile
Retrieve a file by ID.
const file = await client.app.storage.getFile(fileId);Parameters: fileId — string (ID returned from uploadFile or from file metadata).
Returns: Promise<File>.
app.storage.deleteFile
Remove a file from app storage.
await client.app.storage.deleteFile(fileId);Parameters: fileId — string.
app.storage.getFiles
List files with optional pagination.
const result = await client.app.storage.getFiles({
pageNumber: 1,
pageSize: 20,
});
// result: { data: FileMetadata[], pageNumber, pageSize, isLastPage }Parameters (optional):
| Parameter | Type | Description |
|---|---|---|
pageNumber | number | Page number (optional). |
pageSize | number | Items per page (optional). |
Returns: Promise<GetFilesResponse> — { data: FileMetadata[]; pageNumber: number; pageSize: number; isLastPage: boolean }.
FileMetadata: { url: string; id: string; name: string; size: number }.
record.storage
Record-scoped file storage. Available only in Record components via client.context.record.storage after initializeContext(). Use it to attach files to the current record.
| Method | Description |
|---|---|
record.storage.uploadFile() | Upload a file to the current record. |
record.storage.getFiles() | List files for the current record. |
Record storage does not expose getFile or deleteFile; files are managed in the context of the record.
record.storage.uploadFile
Upload a file to the current record.
await client.initializeContext();
const { record } = client.context;
if (record?.storage) {
const { url, id } = await record.storage.uploadFile(file);
}Parameters: file — a File.
Returns: Promise<{ url: string; id: string }>.
record.storage.getFiles
List files attached to the current record, with optional pagination.
await client.initializeContext();
const { record } = client.context;
if (record?.storage) {
const result = await record.storage.getFiles({
pageNumber: 1,
pageSize: 20,
});
console.log(result.data); // FileMetadata[]
console.log(result.isLastPage);
}Parameters (optional): Same as app.storage.getFiles — { pageNumber?: number; pageSize?: number }.
Returns: Promise<GetFilesResponse> — same shape as app storage.
Storage examples
Example 1: Upload and list in a Record component
await client.initializeContext();
const { record } = client.context;
// Upload a file to the current record
if (record?.storage) {
const { id, url } = await record.storage.uploadFile(file);
}
// List files on the record
if (record?.storage) {
const { data, isLastPage } = await record.storage.getFiles({ pageSize: 10 });
data.forEach((f) => console.log(f.name, f.size));
}Example 2: App-level storage with pagination
// List all app files, page by page
const res = await client.app.storage.getFiles({ pageNumber: 1, pageSize: 20 });System Methods
In addition to data operations, the SDK provides methods to control UI elements in the Fireberry platform.
| Method | Description |
|---|---|
system.badge.show() | Display a badge notification |
system.badge.hide() | Hide the badge notification |
system.callbar.show() | Display a callbar with call info |
system.callbar.hide() | Hide the callbar |
Badge
Display notification badges to alert users about important information or status updates.
Show Badge
Display a badge with a number and type indicator.
await client.system.badge.show({
number: 5,
badgeType: "info",
});Parameters:
| Parameter | Type | Description |
|---|---|---|
number | number | The number to display on the badge |
badgeType | 'success' | 'warning' | 'error' | 'info' | Visual style of the badge |
Badge Types:
success— Green badge for positive notificationswarning— Yellow badge for warningserror— Red badge for errors or critical alertsinfo— Blue badge for informational messages
Example:
// Show unread messages count
await client.system.badge.show({
number: 12,
badgeType: "info",
});
// Show error count
await client.system.badge.show({
number: 3,
badgeType: "error",
});Hide Badge
Remove the badge notification.
await client.system.badge.hide();Callbar
Display a callbar interface with call information and related records.
Show Callbar
Display a callbar with call status and associated record information.
await client.system.callbar.show({
callInfo: {
number: 1234567890,
status: "Talking",
},
objectConfig: [
{
objectType: "1",
order: 1,
fields: [{ name: "accountname" }, { name: "email" }],
},
],
placemment: "bottom-end",
});Parameters:
| Parameter | Type | Description |
|---|---|---|
callInfo | CallInfo | Information about the current call |
objectConfig | ObjectConfig[] | Configuration for displaying records |
placemment | 'bottom-start' | 'bottom-end' | Position of the callbar |
CallInfo:
| Field | Type | Description |
|---|---|---|
number | number | Phone number of the call |
status | 'Talking' | 'Ringing' | 'Missed' | 'Dialing' | Current status of the call |
ObjectConfig:
| Field | Type | Description |
|---|---|---|
objectType | string | The object type to display records from |
fields | Field[] | Array of fields to show |
order | number | Display order (optional) |
Field:
| Field | Type | Description |
|---|---|---|
name | string | Field name |
Example:
// Display callbar for incoming call
await client.system.callbar.show({
callInfo: {
number: 5551234567,
status: "Ringing",
},
objectConfig: [
{
objectType: "1",
fields: [{ name: "accountname" }, { name: "phone" }, { name: "email" }],
},
],
placemment: "bottom-end",
});Hide Callbar
Remove the callbar from display.
await client.system.callbar.hide();Toasts
Display temporary notification messages to provide feedback to users about actions, status updates, or important information.
Show Toast
Display a toast notification with customizable content, styling, and behavior.
await client.system.toast.show({
content: "Record saved successfully!",
toastType: "success",
placement: "top-end",
withCloseButton: true,
autoDismissTimeout: 5000,
});Parameters:
| Parameter | Type | Description | Default |
|---|---|---|---|
content | string | The message text to display in the toast | — |
toastType | 'success' | 'warning' | 'error' | 'info' | Visual style of the toast | — |
placement | ToastPlacement | Position where the toast appears | — |
withCloseButton | boolean | Whether to show a close button (optional) | true |
autoDismissTimeout | number | Time in milliseconds before auto-dismiss (optional) | 3000 |
Toast Types:
success— Green toast for successful operationswarning— Yellow toast for warnings or cautionserror— Red toast for errors or failuresinfo— Blue toast for informational messages
Placement Options:
| Placement | Description |
|---|---|
top-left | Top left corner (absolute) |
top-center | Top center |
top-right | Top right corner (absolute) |
top-start | Top start (left in LTR, right in RTL) |
top-end | Top end (right in LTR, left in RTL) |
bottom-left | Bottom left corner (absolute) |
bottom-center | Bottom center |
bottom-right | Bottom right corner (absolute) |
bottom-start | Bottom start (left in LTR, right in RTL) |
bottom-end | Bottom end (right in LTR, left in RTL) |
NoteUse
start/endplacements for internationalized applications to automatically adapt to right-to-left (RTL) languages. Useleft/rightfor absolute positioning.
Optional Parameters:
withCloseButton— Whentrue, displays an X button to manually dismiss the toast. Defaults totrueautoDismissTimeout— Time in milliseconds before the toast automatically disappears. Defaults to3000(3 seconds). Set to0or omit to disable auto-dismiss
Examples:
// Success notification with auto-dismiss
await client.system.toast.show({
content: "Changes saved successfully!",
toastType: "success",
placement: "top-end",
autoDismissTimeout: 5000,
});
// Error notification with close button (using defaults)
await client.system.toast.show({
content: "Failed to save. Please try again.",
toastType: "error",
placement: "top-center",
// withCloseButton defaults to true
// autoDismissTimeout defaults to 3000ms
});
// Warning without auto-dismiss
await client.system.toast.show({
content: "This action cannot be undone.",
toastType: "warning",
placement: "bottom-start",
autoDismissTimeout: 0, // Disable auto-dismiss
});
// Info notification without close button
await client.system.toast.show({
content: "Processing in background...",
toastType: "info",
placement: "bottom-end",
withCloseButton: false,
});Hide Toast
Manually dismiss the currently displayed toast.
await client.system.toast.hide();TypeScript Support
The SDK includes full TypeScript definitions. You can provide two generic type parameters for stronger typing:
import FireberryClientSDK from "@fireberry/sdk/client";
const client = new FireberryClientSDK<ResponseDataType, SettingsType>();
// ^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^
// 1st: API data 2nd: Settings shape| Generic | Purpose | Default |
|---|---|---|
ResponseDataType | Shape of data returned by api.query(), api.create(), etc. | any |
SettingsType | Shape of the value stored by app.settings.get() / app.settings.set() | JsonValue |
Example
import FireberryClientSDK from "@fireberry/sdk/client";
// Define the shape of records your API calls return
interface Account {
accountid: string;
accountname: string;
status: string;
telephone1?: string;
}
// Define the shape of your app's settings
interface MySettings {
theme?: string;
pinnedItems?: { id: string; name: string }[];
}
// Create a fully-typed client
const client = new FireberryClientSDK<Account, MySettings>();
await client.initializeContext();
// API responses are typed
const results = await client.api.query(1, {
fields: "accountid,accountname,status",
query: 'status = "active"',
});
// results.data is typed as Account
// Settings are typed
const settings = await client.app.settings.get();
// settings is typed as MySettings
NoteIf you only need to type API responses and don't use the Settings API, you can pass a single generic as before:
new FireberryClientSDK<Account>().
Extending SDK Types with Declaration Merging
If your Fireberry organization has custom objects, you can register them with the SDK's type system using TypeScript declaration merging. This gives you type-safe object type IDs across your entire app — the compiler will catch typos and invalid object types.
Step 1. Create a declaration file that augments the Objects interface with your custom object types:
// fireberry.d.ts
import "@fireberry/sdk/client";
declare module "@fireberry/sdk/client" {
interface Objects {
shipment: 1001;
warehouse: 1002;
}
}Step 2. Create a runtime constants object that includes your custom entries alongside the built-in ones:
// objects.ts
import { OBJECTS } from "@fireberry/sdk/client";
import type { Objects } from "@fireberry/sdk/client";
export const objects = {
...OBJECTS,
shipment: 1001,
warehouse: 1002,
} as const satisfies Objects;The satisfies Objects check ensures that your runtime values match the types you declared in Step 1. If they drift apart, TypeScript will flag it.
Step 3. Use your constants with SDK methods — TypeScript now recognizes them as valid object types:
import FireberryClientSDK from "@fireberry/sdk/client";
import { objects } from "./objects";
const client = new FireberryClientSDK();
await client.initializeContext();
const fields = await client.api.metadata.getFields(objects.shipment);
const results = await client.api.query(objects.warehouse, {
fields: "warehouseid,name,location",
query: 'location = "US-East"',
});
TipMake sure your
tsconfig.jsonincludearray covers the.d.tsfile. If the file is insrc/, the default"include": ["src"]is sufficient.
Complete Example
A React component that displays and updates data:
import { useEffect, useState } from "react";
import FireberryClientSDK from "@fireberry/sdk/client";
function TaskList() {
const [client] = useState(() => new FireberryClientSDK());
const [tasks, setTasks] = useState([]);
const [loading, setLoading] = useState(true);
useEffect(() => {
async function init() {
await client.initializeContext();
const result = await client.api.query(1, {
fields: "accountid,accountname,status",
query: 'status != "completed"',
});
if (result.success) {
setTasks(Array.isArray(result.data) ? result.data : [result.data]);
}
setLoading(false);
}
init();
}, [client]);
const completeTask = async (taskId) => {
const result = await client.api.update(1, taskId, { status: "completed" });
if (result.success) {
setTasks(tasks.filter((t) => t.accountid !== taskId));
}
};
if (loading) return <div>Loading...</div>;
return (
<ul>
{tasks.map((task) => (
<li key={task.accountid}>
{task.accountname}
<button onClick={() => completeTask(task.id)}>Complete</button>
</li>
))}
</ul>
);
}Cleanup
When your component unmounts, clean up the SDK:
// Clean up event listeners and pending requests
client.destroy();In React:
useEffect(() => {
const client = new FireberryClientSDK();
// ... setup
return () => client.destroy();
}, []);Timeouts
API requests timeout after 60 seconds by default. If a request takes longer, the promise rejects with a timeout error.
Next Steps
- Design System — Build UIs with Fireberry components
- Component Types — Understand context availability by component type
- CLI — Deploy and manage your apps
Updated 1 day ago
