TypeScript SDK
The TypeScript SDK (@fabric-platform/sdk) provides a type-safe client for the Fabric REST API with zero runtime dependencies.
Installation
Section titled “Installation”npm install @fabric-platform/sdkAll imports come from the root package — no sub-path imports needed:
import { FabricClient, verifyWebhookSignature } from "@fabric-platform/sdk";import type { DomainEvent, WorkflowRun, EventKind } from "@fabric-platform/sdk";Client Setup
Section titled “Client Setup”import { FabricClient } from "@fabric-platform/sdk";
// API key auth (server-side)const fabric = new FabricClient({ baseUrl: "https://api.fabric.ai", auth: { type: "api-key", key: "fab_your_key_here" }, organizationId: "org-uuid",});
// Bearer token auth (client-side)const fabric = new FabricClient({ auth: { type: "bearer", token: "jwt-token" },});
// OAuth client credentialsconst fabric = new FabricClient({ auth: { type: "oauth", clientId: "...", clientSecret: "..." },});
// Dynamic token (Next.js server components)const fabric = new FabricClient({ auth: () => getTokenFromCookies(),});
// Consumer app auth (token exchange)const fabric = new FabricClient({ app: { clientId: process.env.FABRIC_CLIENT_ID!, clientSecret: process.env.FABRIC_CLIENT_SECRET!, },});// Act on behalf of a user:const userFabric = await fabric.asUser(userId);
// Debug mode — logs all requests/responsesconst fabric = new FabricClient({ debug: true, onRequest: (method, url) => console.log(`→ ${method} ${url}`), onResponse: (method, url, status, ms) => console.log(`← ${status} (${ms}ms)`),});Configuration Options
Section titled “Configuration Options”| Option | Type | Description |
|---|---|---|
baseUrl | string | Fabric API URL (default: https://gofabric.dev) |
auth | AuthConfig | API key, bearer, OAuth, or dynamic token function |
organizationId | string? | Default org ID for scoped requests |
teamId | string? | Default team ID for scoped requests |
timeout | number | Request timeout in ms (default: 30000) |
fetch | typeof fetch | Custom fetch (e.g., Next.js enhanced fetch) |
debug | boolean | Log all requests/responses to console |
onRequest | RequestInterceptor | Hook called before each request |
onResponse | ResponseInterceptor | Hook called after each response |
app | { clientId, clientSecret } | Consumer app credentials for token exchange |
Authentication
Section titled “Authentication”// Sign up / log inconst auth = await fabric.auth.signup("user@example.com", "password");const auth = await fabric.auth.login("user@example.com", "password");
// Token refreshconst newAuth = await fabric.auth.refresh(auth.refresh_token);
// Passwordlessawait fabric.auth.magicLink("user@example.com");await fabric.auth.forgotPassword("user@example.com");await fabric.auth.resetPassword(accessToken, "new-password");
// Email verificationawait fabric.auth.verify(verificationToken);
// Social login (returns redirect URL)const url = fabric.auth.socialLoginUrl("google");
// MFAconst enrollment = await fabric.auth.mfa.enroll("totp", "My Phone");const challenge = await fabric.auth.mfa.challenge(factorId);const verified = await fabric.auth.mfa.verify(factorId, challengeId, "123456");await fabric.auth.mfa.unenroll(factorId);Identity
Section titled “Identity”const me = await fabric.me.get();const myOrgs = await fabric.me.organizations();const myTeams = await fabric.me.teams();const myPerms = await fabric.me.permissions();Organizations
Section titled “Organizations”// CRUDconst org = await fabric.organizations.create({ name: "Acme Corp" });const orgs = await fabric.organizations.list();const org = await fabric.organizations.get(orgId);await fabric.organizations.update(orgId, { name: "New Name" });await fabric.organizations.archive(orgId);
// Members & teamsconst teams = await fabric.organizations.teams(orgId);const members = await fabric.organizations.members(orgId);const perms = await fabric.organizations.permissions(orgId);
// Settingsconst settings = await fabric.organizations.getSettings(orgId);await fabric.organizations.updateSettings(orgId, { display_name: "Acme Corp" });
// Usage & budgetconst usage = await fabric.organizations.usage(orgId);const daily = await fabric.organizations.usageDaily(orgId, { from: "2026-01-01", group_by: "provider" });const records = await fabric.organizations.usageRecords(orgId);const budget = await fabric.organizations.getBudget(orgId);await fabric.organizations.setBudget(orgId, 500.0);
// Secrets (BYOK provider keys)await fabric.organizations.createSecret(orgId, { name: "OPENAI_API_KEY", value: "sk-..." });const secrets = await fabric.organizations.listSecrets(orgId);await fabric.organizations.deleteSecret(orgId, "OPENAI_API_KEY");
// Audit & exportconst logs = await fabric.organizations.auditLogs(orgId);await fabric.organizations.export(orgId);await fabric.organizations.requestDeletion(orgId);Workflows
Section titled “Workflows”Registry
Section titled “Registry”// Register a workflowconst entry = await fabric.workflows.registry.create({ name: "video/ai_shorts", language: "python", source: "builtin",});
// List & resolveconst workflows = await fabric.workflows.registry.list();const entry = await fabric.workflows.registry.get("video/ai_shorts");await fabric.workflows.registry.delete("video/ai_shorts");
// Compose workflows into a pipelineconst composed = await fabric.workflows.compose({ name: "research-to-video", steps: ["research/deep_research", "video/ai_shorts"],});
// Estimate cost before runningconst estimate = await fabric.workflows.estimate("video/ai_shorts", { input: { topic: "AI trends" },});// Submit a workflow runconst run = await fabric.workflows.runs.submit("video/ai_shorts", { input: { topic: "AI trends", style: "professional" }, metadata: { requested_by: "campaign-123" }, priority: 90,});
// List & get runsconst runs = await fabric.workflows.runs.list();const run = await fabric.workflows.runs.get(runId);
// Controlawait fabric.workflows.runs.cancel(runId, "no longer needed");await fabric.workflows.runs.pause(runId);await fabric.workflows.runs.resume(runId);await fabric.workflows.runs.recover(runId);
// HITL approvalawait fabric.workflows.runs.signal(runId, "approval", { approved: true });await fabric.workflows.runs.approve(runId, { approved: true, reason: "looks good" });const waiting = await fabric.workflows.runs.listWaiting();
// Node-level debuggingconst attempts = await fabric.workflows.runs.getNodeAttempts(runId, "transcribe");Artifacts — Accessing Output Files
Section titled “Artifacts — Accessing Output Files”runs.getOutput(runId) returns a typed RunOutput with per-variant artifacts already grouped under each outputs[i].artifacts entry, with signed download_urls populated:
const result = await fabric.workflows.runs.getOutput(runId);
for (const variant of result.outputs) { for (const a of variant.artifacts) { console.log(a.filename, a.content_type, a.download_url, a.variant_index); }}For “give me every file across every variant in one flat list”, use downloadAllArtifacts:
const downloads = await fabric.workflows.runs.downloadAllArtifacts(runId);// → [{ artifact, filename, data: ArrayBuffer }, ...]You can also list raw artifacts (no signed URLs) via artifactsWithUrls(runId) (which still works) or artifacts(runId).
Submit and Wait
Section titled “Submit and Wait”// Submit and block until completion (with event streaming)const completedRun = await fabric.workflows.runs.submitAndWait("video/ai_shorts", { input: { topic: "AI trends" }, onEvent: (event) => console.log(event.kind, event.node_key), timeoutMs: 600_000, // 10 minutes});Submit and Get Output
Section titled “Submit and Get Output”submitAndGetOutput combines submit + wait + getOutput into one call. Returns a typed RunOutput whose outputs array always has one entry per variant (default outputs.length === 1):
const result = await fabric.workflows.runs.submitAndGetOutput("video/ai_shorts", { input: { topic: "AI trends" },});
for (const variant of result.outputs) { console.log(variant.workflow_name, variant.kind, variant.output); for (const a of variant.artifacts) { console.log(" →", a.filename, a.download_url); // signed, no auth needed }}Variants — Run N Copies of One Workflow
Section titled “Variants — Run N Copies of One Workflow”Set variants (1–10) to fan out N parallel runs of the same workflow with the same input. Each gets its own subprocess and produces its own entry in outputs:
const result = await fabric.workflows.runs.submitAndGetOutput("video/ai_shorts", { input: { topic: "AI trends" }, variants: 3,});
result.outputs.length; // 3result.outputs[0].variant_index; // 0result.outputs[1].variant_index; // 1result.outputs[2].variant_index; // 2The SDK lifts the convenience kwarg into input.variants on the wire — variants is part of the workflow input contract, validated server-side (1–10).
Bundle — Run N Different Workflows
Section titled “Bundle — Run N Different Workflows”A bundle runs N independent sub-workflows in parallel from a single submission. Each entry’s output is tagged with its sub-workflow_name and (when the workflow declared one) kind, so consumer UIs can route each entry to the right card layout / post template:
const result = await fabric.workflows.runs.submitBundle({ bundle: [ { workflow: "video/ai_shorts", input: { topic: "AI trends" } }, { workflow: "image/generate-post", input: { topic: "AI trends", slides: 6 } }, { workflow: "content/threads-post", input: { topic: "AI trends" } }, ],});
for (const variant of result.outputs) { switch (variant.kind) { case "video": /* render a video card */ break; case "carousel": /* render a carousel card */ break; case "image": /* render an image card */ break; case "text": /* render a text card */ break; }}bundle and variants are mutually exclusive — bundle is “N different workflows”, variants is “N copies of one”. The server returns 400 if both are set.
Regenerate — Create a New Run as a Variation of an Existing One
Section titled “Regenerate — Create a New Run as a Variation of an Existing One”Pass regenerate on submit to mark the run as a regeneration of an earlier run/variant. The server persists parent_run_id + parent_variant_index as run lineage; workflows that care read direction / keep / extra_instructions off input.regenerate and modulate their prompts:
const result = await fabric.workflows.runs.submitAndGetOutput("video/ai_shorts", { input: { topic: "AI trends", regenerate: { direction: "punchier", // or deeper / contrarian / visual / data-first / surprise keep: ["platform", "tone_of_voice"], extra_instructions: "shorter, tighter hooks", parent_run_id: priorRun.id, parent_variant_index: 0, }, },});What direction actually does
Section titled “What direction actually does”direction is a prompt-level hint — workflows opt in to honor it. The lineage columns (parent_run_id, parent_variant_index) always persist regardless of which workflow you target; the prompt-modulating bits (direction, keep, extra_instructions) are read by stages via regenerateDirective(input.regenerate) and prepended to the relevant LLM/image prompt.
| Workflow | What direction shifts |
|---|---|
image/generate | Both the visual prompt and the overlay-text distillation — "punchier" yields a tighter hook + sharper composition, "contrarian" flips the angle, etc. |
For workflows not on this list, direction is silently ignored — the run still executes and lineage still records, but the output is whatever the unmodulated prompt produces.
Replay payloads — only send inputs
Section titled “Replay payloads — only send inputs”When you kick off a regen by replaying a previous run’s variant data, strip the output-shaped fields before submitting. Workflows declare their input contract narrowly (e.g. image/generate reads topic, hook, platform, thumbnail_text, thumbnail_style, num_thumbnails); fields like thumbnail_paths, thumbnail_asset_ids, selected_thumbnail, overlay_text, thumbnail_size, platform_exports, evaluation, video_asset_id are workflow outputs and should be filtered out of the replay. They survive validation as pass-through extras (so the run won’t fail), but they’re noise in storage and may surprise a future stage if it starts reading them.
A small stripFabricInternals(input) helper that drops the _fabric_* keys plus the per-workflow output keys is the cleanest place to centralize this.
Output Shape — Uniform Across Variants, Bundle, and Single
Section titled “Output Shape — Uniform Across Variants, Bundle, and Single”runs.getOutput(runId) and runs.submitAndGetOutput(...) return a typed RunOutput:
interface RunOutput { run_id: string; status: string; error: string | null; variants: number; // count, equals outputs.length outputs: VariantOutput[]; // one entry per variant; default 1 nodes: RunNodeOutput[];}
interface VariantOutput { variant_index: number; workflow_name: string | null; // sub-workflow that produced this entry kind: "video" | "carousel" | "image" | "text" | null; output: unknown | null; // the workflow's terminal output artifacts: RunArtifact[]; // produced by this variant only}Single-workflow runs have outputs.length === 1; you iterate the array uniformly — no shape branching.
Watching Workflow Runs (Real-Time)
Section titled “Watching Workflow Runs (Real-Time)”The watch() method is the recommended way to observe workflow execution step-by-step:
const watcher = fabric.workflows.runs.watch(runId, { // Optional: only watch specific nodes nodeKeys: ["transcribe", "render", "compose"],
// Typed callbacks onNodeStarted: (key, payload) => console.log(`▶ ${key} started`), onNodeProgress: (key, payload) => console.log(`⏳ ${key}: ${payload.percentage}%`), onNodeCompleted: (key, payload) => console.log(`✓ ${key} done`), onNodeFailed: (key, payload) => console.error(`✗ ${key} failed:`, payload),
onRunCompleted: (payload) => console.log("Workflow finished!"), onRunFailed: (payload) => console.error("Workflow failed:", payload), onRunCancelled: (payload) => console.log("Workflow cancelled"),
// Auto-reconnects on connection drop (default: true) reconnect: true,});
// Stop watching earlywatcher.abort();
// Or wait until the run completesawait watcher.done;Browser usage — direct streaming with bearer auth
Section titled “Browser usage — direct streaming with bearer auth”watch() uses fetch + ReadableStream under the hood, not the native
EventSource, so it works directly from the browser with custom
Authorization headers. No proxy hop is required — your frontend can talk
to the Fabric API directly.
The recommended auth pattern in the browser is a dynamic token provider that fetches a short-lived token from your own backend:
'use client';import { FabricClient } from "@fabric-platform/sdk";
export const fabric = new FabricClient({ baseUrl: "https://api.fabric.example.com", auth: async () => { const res = await fetch("/api/fabric-token", { credentials: "include" }); const { token } = await res.json(); return token; },});For React apps, the SDK ships a hook that wraps watch() and tracks node
progress as typed state:
'use client';import { useState } from "react";import { useWorkflowRun } from "@fabric-platform/sdk/react";import { fabric } from "./fabric-client";
export function RunMonitor({ workflowName }: { workflowName: string }) { const [runId, setRunId] = useState<string | null>(null); const run = useWorkflowRun(fabric, runId);
return ( <> <button disabled={runId !== null && !run.isComplete} onClick={async () => { const r = await fabric.workflows.runs.submit(workflowName, { input: {}, }); setRunId(r.id); }} > Run </button> <progress value={run.progressPercent} max={100} /> <p>{run.currentStep ?? (runId ? "waiting…" : "idle")}</p> {run.isComplete && <p>Done: {run.runStatus}</p>} </> );}The hook cleans up the underlying stream on unmount, surfaces errors on
run.error rather than throwing, and accepts runId: null as a no-op so
you can render it before the run has been submitted.
CORS: the Fabric API must allow the caller’s origin, and its
allow_headers list must include Authorization, Cache-Control, and
Last-Event-ID. The default tower_http::cors config that ships with
fabric serve already does.
See also: usePipelineProgress (same-origin proxy variant using
EventSource) and the Streaming Events guide
for the full picture.
Event Streaming (SSE)
Section titled “Event Streaming (SSE)”For lower-level event streaming with filtering:
// Stream all eventsconst stream = fabric.events.stream({ onEvent: (event) => console.log(event.kind), filter: { kinds: ["workflow.run.completed", "workflow.run.failed"] }, reconnect: true,});
// Stream events for a specific runconst stream = fabric.events.streamRun(runId, { onEvent: (event) => console.log(event.kind, event.node_key), filter: { nodeKeys: ["transcribe", "render"] }, reconnect: true,});
// Stream events for a specific job (single node)const stream = fabric.events.streamJob(jobId, { onEvent: (event) => console.log(event),});
// Stop streamingstream.abort();await stream.done;WebSocket (Bidirectional)
Section titled “WebSocket (Bidirectional)”const ws = fabric.events.connectWebSocket({ onEvent: (event) => console.log(event), onAck: (ack) => console.log("Server ack:", ack), filter: { kinds: ["workflow.node.progress"] },});
// Subscribe to a run dynamicallyws.subscribeToRun(runId);
// Unsubscribews.unsubscribe();
// Closews.close();Webhooks (Terminal Notifications)
Section titled “Webhooks (Terminal Notifications)”Webhooks fire when a workflow run reaches a terminal state (completed/failed/cancelled). Use them for backend integrations and async pipelines.
Managing Webhooks
Section titled “Managing Webhooks”// Create a webhookconst webhook = await fabric.webhooks.create(orgId, { url: "https://your-app.com/webhook", event_filter: ["workflow.run.completed", "workflow.run.failed"], resource_filter: { workflow_definition_id: "..." }, max_retries: 5,});
// List, update, deleteconst webhooks = await fabric.webhooks.list(orgId);await fabric.webhooks.update(webhookId, { active: false });await fabric.webhooks.delete(webhookId);
// View delivery attemptsconst deliveries = await fabric.webhooks.deliveries(webhookId);Verifying Webhook Signatures
Section titled “Verifying Webhook Signatures”Every webhook delivery is signed with HMAC-SHA256. Use constructWebhookEvent() to verify and parse in one call:
import { constructWebhookEvent } from "@fabric-platform/sdk";
app.post("/webhook", async (req, res) => { let event; try { event = await constructWebhookEvent( req.body, // raw body string req.headers["x-fabric-signature"]!, // sha256=<hex> process.env.WEBHOOK_SECRET!, ); } catch { return res.status(401).send("Invalid signature"); }
switch (event.kind) { case "workflow.run.completed": // Fetch output artifacts with download links const artifacts = await fabric.workflows.runs.artifactsWithUrls(event.run_id!); console.log("Output files:", artifacts.map(a => a.download_url)); break; case "workflow.run.failed": console.error("Run failed:", event.payload); break; }
res.sendStatus(200);});Or verify separately:
import { verifyWebhookSignature } from "@fabric-platform/sdk";
const valid = await verifyWebhookSignature(rawBody, signature, secret);Face Swap & Motion Transfer
Section titled “Face Swap & Motion Transfer”Use the built-in video/face-swap and video/motion-transfer workflows to create persona content:
import type { FaceSwapInput, MotionTransferInput } from "@fabric-platform/sdk";
// Face swap — swap a persona face onto a source imageconst run = await fabric.workflows.runs.submitAndWait("video/face-swap", { input: { source_url: "https://example.com/dance-still.jpg", target_url: "https://example.com/persona-face.png", } satisfies FaceSwapInput,});console.log(run.output?.face_swap_url);
// Or pull the persona from an org galleryconst run = await fabric.workflows.runs.submitAndWait("video/face-swap", { input: { source_url: "https://example.com/dance-still.jpg", persona_gallery_id: "gallery-uuid", persona_index: 0, } satisfies FaceSwapInput,});
// Motion transfer — animate a persona with a reference video's motionconst run = await fabric.workflows.runs.submitAndWait("video/motion-transfer", { input: { source_image_url: "https://example.com/persona.png", driving_video_url: "https://example.com/dance-reference.mp4", } satisfies MotionTransferInput,});console.log(run.output?.motion_transfer_url);
// With Seedance for full-body motionconst run = await fabric.workflows.runs.submitAndWait("video/motion-transfer", { input: { driving_video_url: "https://example.com/choreography.mp4", persona_gallery_id: "gallery-uuid", motion_model: "seedance/2.0", } satisfies MotionTransferInput,});
// Download the resultconst artifacts = await fabric.workflows.runs.artifactsWithUrls(run.id);console.log(artifacts[0].download_url);AI Providers
Section titled “AI Providers”Execute AI providers directly with optional BYOK credentials:
// List available providersconst capabilities = await fabric.providers.list();
// Execute (request/response)const result = await fabric.providers.execute({ modality: "text", model: "gpt-4o", input: { prompt: "Summarize this article..." }, credentials: { OPENAI_API_KEY: "sk-..." }, // BYOK (optional)});
// Streaming execution (SSE)const stream = fabric.providers.executeStream( { modality: "text", input: { prompt: "..." } }, { onChunk: (chunk) => process.stdout.write(chunk.delta), onComplete: (result) => console.log("\nDone:", result.usage), },);
// Cost estimationconst cost = await fabric.providers.estimate({ modality: "text", model: "gpt-4o", input: {} });Assets
Section titled “Assets”// Upload a file (max 100 MB)const asset = await fabric.assets.upload(fileBlob, { contentType: "video/mp4", filename: "output.mp4",});
// List assetsconst assets = await fabric.assets.list();
// Generate a signed download URLconst { url } = await fabric.assets.signedUrl(assetId, 3600);
// Direct download (returns raw Response)const response = await fabric.assets.download("path/to/file.mp4");Permissions
Section titled “Permissions”// Grant permissionawait fabric.permissions.grant({ principal_id: userId, organization_id: orgId, role: "admin",});
// Check single permissionconst result = await fabric.permissions.check({ resource: `organization:${orgId}`, action: "team.create",});
// Batch checkconst results = await fabric.permissions.checkBatch([ { resource: `organization:${orgId}`, action: "read" }, { resource: `team:${teamId}`, action: "invite" },]);
// List & revokeconst perms = await fabric.permissions.list();await fabric.permissions.revoke(permissionId);Schedules
Section titled “Schedules”// Create a cron scheduleconst schedule = await fabric.schedules.create(workflowDefId, { cron: "0 9 * * MON-FRI", timezone: "America/New_York", enabled: true,});
// Manage schedulesconst schedules = await fabric.schedules.list(workflowDefId);await fabric.schedules.update(scheduleId, { enabled: false });await fabric.schedules.delete(scheduleId);
// Manual triggerawait fabric.schedules.trigger(scheduleId);const history = await fabric.schedules.history(scheduleId);Pagination
Section titled “Pagination”import { paginate, paginateAll, paginateItems } from "@fabric-platform/sdk";
// Page-level iterationfor await (const page of paginate((p) => fabric.organizations.list(p))) { console.log(`Page with ${page.length} orgs`);}
// Item-level iterationfor await (const org of paginateItems((p) => fabric.organizations.list(p))) { console.log(org.name);}
// Collect all into an arrayconst allOrgs = await paginateAll((p) => fabric.organizations.list(p));Error Handling
Section titled “Error Handling”import { FabricError, FabricAuthError, FabricNotFoundError, FabricRateLimitError,} from "@fabric-platform/sdk";
try { await fabric.organizations.get("bad-id");} catch (err) { if (err instanceof FabricNotFoundError) { console.log("Not found:", err.message); } else if (err instanceof FabricRateLimitError) { console.log(`Rate limited, retry after ${err.retryAfterMs}ms`); } else if (err instanceof FabricAuthError) { console.log("Authentication failed"); } else if (err instanceof FabricError) { console.log(`${err.code} (${err.status}): ${err.message}`); console.log("Request ID:", err.requestId); }}Consumer Apps
Section titled “Consumer Apps”Register and manage consumer apps. See the App Registration guide for the full setup flow.
// Register a new app (returns client credentials — shown once)const app = await fabric.apps.create({ name: "My App" });console.log(app.client_id, app.client_secret);
// List your appsconst apps = await fabric.apps.list();
// Update settingsawait fabric.apps.update(appId, { auto_create_org: false, allowed_origins: ["https://myapp.com"],});
// Rotate client secretconst { client_secret } = await fabric.apps.rotateSecret(appId);
// Aggregate usage across all orgs in the appconst usage = await fabric.apps.usage(appId);Acting on Behalf of Users
Section titled “Acting on Behalf of Users”const fabric = new FabricClient({ app: { clientId: "...", clientSecret: "..." },});
// Token exchange: get a user-scoped clientconst userFabric = await fabric.asUser(userId);
// All operations scoped to this user's app-orgawait userFabric.workflows.runs.submit("video/ai_shorts", { input: { ... } });await userFabric.organizations.list(); // Only this app's orgs// Bootstrap (dev mode)await fabric.admin.bootstrap();
// System infoconst info = await fabric.admin.systemInfo();const status = await fabric.admin.systemStatus();
// Concurrency limitsconst limits = await fabric.admin.listConcurrencyLimits();await fabric.admin.setConcurrencyLimit("org:uuid", 10);
// Standalone audit logsconst logs = await fabric.admin.auditLogs();Event Kinds
Section titled “Event Kinds”All event kinds emitted by the platform:
| Category | Event Kinds |
|---|---|
| Run lifecycle | workflow.run.created, queued, promoted, started, completed, failed, cancelled, waiting, paused |
| Node lifecycle | workflow.node.ready, claimed, started, progress, completed, failed, retried, skipped, cancelled, waiting_for_event, resumed |
| Job lifecycle | job.created, started, completed, failed |
| Schedule | workflow.schedule.triggered, skipped, failed |
| Webhook | webhook.delivery.exhausted |
| Tenancy | organization.created, team.created, membership.created, invitation.created, accepted, revoked |
Resources
Section titled “Resources”The SDK provides 20 resource classes, all accessible as properties on FabricClient:
| Property | Resource |
|---|---|
fabric.auth | Authentication (signup, login, MFA) |
fabric.me | Current user profile |
fabric.organizations | Organization CRUD, settings, usage, secrets |
fabric.teams | Team CRUD |
fabric.workflows | Registry, runs, composition, estimation |
fabric.events | SSE, WebSocket, event streaming |
fabric.assets | Upload, download, signed URLs |
fabric.galleries | Gallery CRUD, items |
fabric.apiKeys | API key CRUD, rotate, disable |
fabric.invitations | Invite, accept, revoke |
fabric.permissions | Grant, check, batch check, revoke |
fabric.webhooks | Webhook CRUD, delivery history |
fabric.serviceAccounts | Service account CRUD, API keys |
fabric.oauth | OAuth client management, token exchange |
fabric.schedules | Cron schedule CRUD, trigger, history |
fabric.providers | AI provider execution, streaming, BYOK |
fabric.packages | Installed package listing |
fabric.admin | System info, concurrency, bootstrap |
fabric.apps | Consumer app registration and management |