TypeScript SDK for the Assembly platform. ESM-only, Node.js 18+ and Bun.
import { createAssemblyKit, KitMode } from "assembly-kit";
// Local mode (default) — only apiKey required
const kit = createAssemblyKit({ apiKey: "your-key" });
// Local mode with workspaceId — compound key: workspaceId/apiKey
const kit = createAssemblyKit({ apiKey: "your-key", workspaceId: "ws-123" });
// Local mode with token — token parsed, compound key from token payload
const kit = createAssemblyKit({ apiKey: "your-key", token: encryptedToken });
// Marketplace mode — either token or workspaceId required
const kit = createAssemblyKit({
apiKey: "your-key",
token: encryptedToken,
kitMode: KitMode.Marketplace,
});kitMode: "local"(default) → onlyapiKeyrequired.workspaceIdandtokenare optional.kitMode: "marketplace"→ eithertokenorworkspaceIdmust be provided.
| Option | Type | Default | Description |
|---|---|---|---|
apiKey |
string |
— | Required. Assembly API key. |
token |
string |
— | Encrypted token. Takes precedence over workspaceId. |
workspaceId |
string |
— | Workspace ID. Required when token is not provided. |
kitMode |
KitMode |
"local" |
"local" or "marketplace". See Quick Start above. |
validateResponses |
boolean |
true |
Validate all API responses through Zod schemas. |
baseUrl |
string |
https://api.assembly.com |
Base URL for all API requests. |
retryCount |
number |
2 |
Number of retry attempts for retryable errors. |
requestsPerSecond |
number |
20 |
Maximum requests per second (sliding-window rate limiter). |
fetch |
typeof globalThis.fetch |
— | Injectable fetch function for testing. |
Access API resources via kit.<namespace>.<method>():
| Namespace | Methods |
|---|---|
workspace |
retrieve() |
me |
retrieve() |
clients |
list() retrieve() retrieveWithAppVisibility() create() update() delete() listAll() |
companies |
list() retrieve() create() update() delete() addClients() listAll() |
internalUsers |
list() retrieve() update() retrieveNotificationSettings() listAll() |
notes |
list() retrieve() create() update() delete() listAll() |
tasks |
list() retrieve() create() update() delete() listAll() |
taskComments |
list() retrieve() delete() listAll() |
taskTemplates |
list() retrieve() listAll() |
invoices |
list() retrieve() create() listAll() |
invoiceTemplates |
list() listAll() |
subscriptions |
list() retrieve() create() cancel() listAll() |
subscriptionTemplates |
list() listAll() |
refunds |
list() create() listAll() |
payments |
list() listAll() |
products |
list() retrieve() create() listAll() |
prices |
list() retrieve() create() listAll() |
contracts |
retrieve() send() |
contractTemplates |
list() retrieve() |
forms |
list() retrieve() create() listSubmissions() listAllSubmissions() listAll() |
formResponses |
list() create() |
files |
list() retrieve() create() delete() retrieveDownloadUrl() download() updateFolderPermissions() updateRootFolderPermissions() listAll() |
fileChannels |
list() retrieve() create() listAll() |
messageChannels |
list() retrieve() create() listUnread() listAll() |
messages |
list() send() listAll() |
events |
list() retrieve() create() listAll() |
notifications |
list() retrieve() create() delete() markRead() markUnread() |
customFields |
list() create() |
customFieldOptions |
list() |
appConnections |
list() create() |
appInstalls |
list() retrieve() retrieveNotificationSettings() createNotificationSettings() updateNotificationSettings() |
listAll() auto-paginates and returns Promise<T[]>. For manual pagination use list() and handle nextToken:
const allCompanies = await kit.companies.listAll();
const page = await kit.companies.list({ limit: 100 });
if (page.nextToken) {
const next = await kit.companies.list({ limit: 100, nextToken: page.nextToken });
}createAssemblyKit accepts optional generic parameters that type the
customFields shape returned from kit.clients.* and kit.companies.*:
// Single shape applied to both clients and companies
const kit = createAssemblyKit<{ roles: string[] }>({ apiKey, workspaceId });
const client = await kit.clients.retrieve("id");
client.customFields; // { roles: string[] } | null | undefined
// Different shapes per resource
const kit = createAssemblyKit<{ roles: string[] }, { industry: string }>({
apiKey,
workspaceId,
});The generics only narrow types — runtime parsing still uses the loose
Record<string, unknown> schema, so unexpected fields won't throw.
Standalone token decryption (not required for normal SDK usage):
import { AssemblyToken, createToken } from "assembly-kit";
const token = new AssemblyToken({ token: encryptedHex, apiKey });
token.workspaceId; // string
token.clientId; // string | undefined
token.companyId; // string | undefined
token.internalUserId; // string | undefined
token.isClientUser; // boolean
token.isInternalUser; // boolean
token.isProxying; // boolean — internal user previewing as a client (both IDs present)
const client = token.ensureIsClient(); // ClientTokenPayload (throws if not client)
const internal = token.ensureIsInternalUser(); // InternalUserTokenPayload (throws if not internal)
// Encrypt a payload into a token
const encrypted = createToken({
payload: { workspaceId: "ws-123", clientId: "cl-1", companyId: "co-1" },
apiKey,
});All errors extend AssemblyError. Import from assembly-kit:
import {
AssemblyError, // base class (statusCode, details)
AssemblyNoTokenError, // 400 — token required but missing
AssemblyInvalidTokenError, // 401 — token decryption/validation failed
AssemblyUnauthorizedError, // 401 — API key rejected or identity assertion failed
AssemblyForbiddenError, // 403 — insufficient permissions
AssemblyNotFoundError, // 404 — resource not found
AssemblyValidationError, // 422 — request payload rejected
AssemblyRateLimitError, // 429 — rate limited (.retryAfter?: number)
AssemblyServerError, // 500 — server error
AssemblyResponseParseError, // 500 — Zod validation failed (.zodError)
AssemblyConnectionError, // 503 — network error
} from "assembly-kit";
try {
await kit.companies.retrieve(id);
} catch (err) {
if (err instanceof AssemblyRateLimitError) {
// err.retryAfter — seconds until retry
} else if (err instanceof AssemblyError) {
// err.message, err.statusCode, err.details
}
}Zod 4 schemas and inferred types for all resources:
import { ClientSchema, CompanySchema, TaskSchema } from "assembly-kit/schemas";
import type { Client, Company, Task } from "assembly-kit/schemas";
// Response schemas (paginated)
import { ClientsResponseSchema } from "assembly-kit/schemas";
// Request schemas
import { ClientCreateRequestSchema } from "assembly-kit/schemas";Use React cache() to deduplicate per request:
import { cache } from "react";
import { createAssemblyKit } from "assembly-kit";
export const getAssemblyKit = cache((apiKey: string, workspaceId: string) =>
createAssemblyKit({ apiKey, workspaceId }),
);| Import path | Key exports |
|---|---|
assembly-kit |
createAssemblyKit, AssemblyKit, errors, schemas, token utils |
assembly-kit/schemas |
All Zod schemas and inferred types |
assembly-kit/client |
createAssemblyKit, AssemblyKit, AssemblyKitOptions |
assembly-kit/errors |
All error classes |
assembly-kit/token |
AssemblyToken, createToken |
assembly-kit/logger |
createLogger, createPrettyLogger, logger (requires pino peer dep; createPrettyLogger also needs pino-pretty) |
assembly-kit/bridge-ui |
usePrimaryCta, useSecondaryCta, useActionsMenu (requires react + @assembly-js/app-bridge peer deps) |