Skip to content

TypeScript SDK

The official TypeScript SDK provides typed methods for all OpenTusk API operations. Zero external dependencies — uses native fetch. The SDK also powers the MCP server under the hood — every MCP tool call maps to an SDK method.

Terminal window
npm install @opentusk/sdk
import { OpenTuskClient } from '@opentusk/sdk';
const opentusk = new OpenTuskClient({
apiKey: 'otk_your_key',
});

For local development, override the base URL:

const opentusk = new OpenTuskClient({
apiKey: 'otk_your_key',
baseUrl: 'http://localhost:8000',
});
const opentusk = new OpenTuskClient({
apiKey: 'otk_...',
baseUrl: 'http://localhost:8000', // Override API URL
headers: { 'X-Custom': 'value' }, // Extra headers on every request
fetch: customFetchFn, // Custom fetch implementation
});
NamespaceDescription
opentusk.vaultsCreate, list, update, delete vaults
opentusk.filesUpload, download, list, delete files
opentusk.webhooksManage webhook endpoints and deliveries
opentusk.publicAccess public vaults and files (no auth)
opentusk.accountGet account info
opentusk.apiKeysCreate, list, revoke API keys
opentusk.trashList, restore, delete, empty trash
opentusk.sharedVaultsShared vault membership and Sui address linking
opentusk.foldersCreate, list, get contents, update, delete folders
// Create
const vault = await opentusk.vaults.create({
name: 'My Vault',
visibility: 'public',
});
// List all
const vaults = await opentusk.vaults.list();
// Update
await opentusk.vaults.update(vault.id, { name: 'Renamed' });
// Delete (force moves files to trash first)
await opentusk.vaults.delete(vault.id, { force: true });
// Link your Sui address to your account (required once)
await opentusk.sharedVaults.linkSuiAddress('0x1234...abcd');
// Create a shared vault
const vault = await opentusk.vaults.create({
name: 'Team Vault',
visibility: 'shared',
});
// Grant access to another user by their Sui address
const { member } = await opentusk.sharedVaults.addMember(vault.id, {
suiAddress: '0x5678...efgh',
});
// List all members
const { members } = await opentusk.sharedVaults.listMembers(vault.id);
// Revoke access
await opentusk.sharedVaults.removeMember(vault.id, member.id);
// List shared vaults you've been granted access to
const { vaults } = await opentusk.sharedVaults.list();
// Unlink your Sui address
await opentusk.sharedVaults.unlinkSuiAddress();
import { readFile } from 'fs/promises';
const data = await readFile('./photo.jpg');
const file = await opentusk.files.upload({
name: 'photo.jpg',
mimeType: 'image/jpeg',
vaultId: vault.id,
data,
});
// 1. Get presigned URL
const { fileId, uploadUrl } = await opentusk.files.requestUpload({
name: 'doc.pdf',
mimeType: 'application/pdf',
sizeBytes: buffer.byteLength,
vaultId: vault.id,
});
// 2. PUT to presigned URL
await fetch(uploadUrl, {
method: 'PUT',
body: buffer,
headers: { 'Content-Type': 'application/pdf' },
});
// 3. Confirm
const file = await opentusk.files.confirmUpload(fileId);

Pass paymentType: 'ppu' to bill this single upload in WAL on Sui, independent of the account’s subscription. The SDK returns a PaymentRequired (HTTP 402) on the first call; sign a WAL transfer, then retry with quoteId + txDigest. See Upload & lifecycle — 402 payment flow for the full pattern.

const result = await opentusk.files.requestUpload({
name: 'doc.pdf',
mimeType: 'application/pdf',
sizeBytes: buffer.byteLength,
vaultId: vault.id,
paymentType: 'ppu', // opt this upload into PPU (any plan)
epochs: 30, // optional; defaults to plan's ppuMinEpochs
});
const { downloadUrl, encryption } = await opentusk.files.getDownloadUrl(file.id);
const response = await fetch(downloadUrl);
const bytes = await response.arrayBuffer();
// If encrypted, decrypt client-side using encryption.wrappedKey and encryption.iv

Wait for a file to reach a specific status:

// Promise-based — resolves when status is reached
const synced = await opentusk.files.waitForStatus(file.id, ['synced'], {
interval: 3000, // poll every 3s (default: 2s)
timeout: 120000, // give up after 2min (default: 60s)
});

Or use the async iterator for progress updates:

for await (const status of opentusk.files.pollStatus(file.id, ['synced'])) {
console.log(`Current status: ${status.status}`);
}
// Create
const folder = await opentusk.folders.create({
vaultId: vault.id,
name: 'Documents',
});
// List
const folders = await opentusk.folders.list({ vaultId: vault.id });
// Get contents (files + subfolders)
const contents = await opentusk.folders.getContents(folder.id);
// Rename
await opentusk.folders.update(folder.id, { name: 'Renamed' });
// Delete
await opentusk.folders.delete(folder.id);
// Create
const webhook = await opentusk.webhooks.create({
url: 'https://example.com/webhook',
events: ['file.synced', 'file.error'],
});
console.log(webhook.secret); // Save this — only shown once
// Test
await opentusk.webhooks.test(webhook.id);
// List deliveries
const deliveries = await opentusk.webhooks.listDeliveries(webhook.id, {
limit: 10,
});
// List trashed items
const items = await opentusk.trash.list();
// Restore
await opentusk.trash.restore(itemId);
// Permanently delete one
await opentusk.trash.delete(itemId);
// Empty all trash
await opentusk.trash.empty();

Public methods don’t require authentication:

// Build public URLs (synchronous, no API call)
const fileUrl = opentusk.public.getFileUrl(fileId);
const blobUrl = opentusk.public.getBlobUrl(walrusBlobId);
// List files in a public vault
const { vault, files } = await opentusk.public.listVaultFiles(userId, 'my-vault');
import { OpenTuskError, OpenTuskTimeoutError } from '@opentusk/sdk';
try {
await opentusk.vaults.get('non-existent');
} catch (err) {
if (err instanceof OpenTuskError) {
console.error(err.statusCode, err.message);
}
if (err instanceof OpenTuskTimeoutError) {
console.error('Polling timed out');
}
}