This guide helps AI coding agents assist developers in quickly building applications with Box Node SDK v10 or above. Focus on getting developers productive fast with best practices and common pitfalls highlighted.
Use Box Node SDK v10 or above - Auto-generated, TypeScript-first SDK.
npm install box-node-sdk # Installs latest (v10+)Why v10+?
- Auto-generated from Box API OpenAPI specs (always up-to-date)
- Full TypeScript support with complete type definitions
- Breaking changes from v3 - NOT backwards compatible
- Built-in retry logic and error handling
npm install
npm run build
npm startRun in one go: Use tsc + node (no tsx). This avoids platform-specific native binaries (esbuild) so npm install && npm start works on any platform. If you use tsx, run npm install on the same machine where you run the app—do not copy node_modules across platforms.
npm init -y
npm install box-node-sdk dotenv
npm install --save-dev typescript @types/nodeUse tsc + node to run (see Step 4). Do not rely on tsx for "one-command" setups—it pulls in esbuild and can fail with wrong-platform binaries if node_modules was copied or installed elsewhere.
- Visit Box Developer Console
- Create Custom App → "OAuth 2.0 with JWT" → Generate Developer Token
- Copy token (
⚠️ expires in 60 min)
// index.ts
import { BoxClient, BoxDeveloperTokenAuth } from 'box-node-sdk';
const auth = new BoxDeveloperTokenAuth({
token: process.env.BOX_DEVELOPER_TOKEN!
});
const client = new BoxClient({ auth });
const items = await client.folders.getFolderItems('0');
items.entries.forEach(item => console.log(`${item.type}: ${item.name}`));BOX_DEVELOPER_TOKEN=your_token npm startOr build once then run: npm run build && node dist/index.js. With a .env containing BOX_DEVELOPER_TOKEN, npm start is enough.
Developer Token (testing only, 60 min expiry)
const auth = new BoxDeveloperTokenAuth({ token: process.env.BOX_DEVELOPER_TOKEN! });JWT - Service Account (production, server-to-server)
const auth = new BoxJwtAuth({
clientId: process.env.BOX_CLIENT_ID!,
clientSecret: process.env.BOX_CLIENT_SECRET!,
enterpriseId: process.env.BOX_ENTERPRISE_ID!,
jwtKeyId: process.env.BOX_JWT_KEY_ID!,
privateKey: process.env.BOX_PRIVATE_KEY!.replace(/\\n/g, '\n'),
privateKeyPassphrase: process.env.BOX_PRIVATE_KEY_PASSPHRASE!
});
const client = auth.getClient(); // Service Account clientCCG - Client Credentials (production, application-level)
const auth = new BoxCcgAuth({
clientId: process.env.BOX_CLIENT_ID!,
clientSecret: process.env.BOX_CLIENT_SECRET!,
enterpriseId: process.env.BOX_ENTERPRISE_ID!
});Critical: JWT authentication uses a Service Account - a special Box account that owns uploaded files.
- File exists but Service Account doesn't have access
- Solution: Collaborate the Service Account with the folder/file
// Add Service Account as collaborator to existing folder
await client.collaborations.createCollaboration({
item: { type: 'folder', id: folderId },
accessible_by: { type: 'user', id: serviceAccountId },
role: 'editor' // or 'viewer', 'previewer', 'uploader', 'co-owner'
});
// Get Service Account ID
const currentUser = await client.users.getUserMe();
console.log('Service Account ID:', currentUser.id);Best Practice: When working with existing Box content:
- Get Service Account ID first
- Add it as collaborator to target folders
- Then perform operations
// Upload file
const upload = await client.uploads.uploadFile({
attributes: { name: 'doc.pdf', parent: { id: '0' } },
file: createReadStream('./doc.pdf')
});
// Create folder
const folder = await client.folders.createFolder({
name: 'My Folder', parent: { id: '0' }
});
// Download file
const stream = await client.downloads.downloadFile(fileId);
await pipeline(stream, createWriteStream('./output.pdf'));
// Search
const results = await client.search.searchForContent({
query: 'contract', queryParams: { type: 'file' }
});
// List with pagination
const items = await client.folders.getFolderItems(folderId, {
queryParams: { limit: 100, offset: 0 }
});Status codes to handle:
401- Token expired (auto-refreshed with JWT/CCG, manual for DevToken)403- Permission denied → Check if Service Account has collaboration access404- Not found → File exists but Service Account not collaborated409- Conflict (e.g., folder name exists)429- Rate limited (implement exponential backoff)500/503- Box service error (retry)
import { BoxSdkError } from 'box-node-sdk';
try {
const file = await client.files.getFileById(fileId);
} catch (error) {
if (error instanceof BoxSdkError) {
if (error.response?.status === 404) {
console.log('File not found - Service Account may need collaboration access');
} else if (error.response?.status === 403) {
console.log('Access denied - Ensure Service Account is collaborated on this item');
}
}
throw error;
}Quick navigation:
- Authentication →
*auth*.ts,box-client.ts - File operations →
services/file*.ts,*upload*.ts - Environment config →
.env,config/ - Tests →
*.test.ts,/tests
Recommended structure:
src/
├── box-client.ts # Client initialization
├── services/
│ ├── file-service.ts
│ └── folder-service.ts
└── index.ts
🔒 Never commit:
- Developer tokens
- JWT private keys
- Client secrets
- Box config JSON files
🔒 Token lifecycle:
- Developer tokens: 60 min, NO auto-refresh
- JWT/CCG access tokens: 60 min, auto-refreshed by SDK
- Always use environment variables
🔒 Service Account security:
- Service Account has admin privileges in enterprise
- Use app users for customer-scoped data
- Apply least privilege principle
Agent can do without asking:
client.files.getFileById()- Read filesclient.folders.getFolderItems()- List contentsnpm test -- <specific-test>- Run single testtsc --noEmit- Type checking
Agent must ask first:
npm install <package>- Installing dependenciesclient.files.deleteFileById()- Deleting contentclient.folders.deleteFolderById()- Deleting folders- Full test suite in CI
- Revoking tokens or collaborations
❌ Using v3 syntax (callbacks)
// Wrong
client.files.get(fileId, null, callback);
// Right
await client.files.getFileById(fileId);❌ Forgetting Service Account collaboration
// Wrong - assuming Service Account has access
await client.files.getFileById(existingFileId); // 404 error!
// Right - check and add collaboration first
const user = await client.users.getUserMe();
await client.collaborations.createCollaboration({
item: { type: 'folder', id: folderId },
accessible_by: { type: 'user', id: user.id },
role: 'editor'
});❌ Hardcoding IDs
// Wrong
const folderId = '123456789';
// Right
const folderId = process.env.BOX_FOLDER_ID!;Agent should escalate when:
- Choosing JWT vs CCG vs OAuth (business requirement)
- Setting up Box app in Developer Console
- Requesting admin authorization for JWT app
- Deciding on Service Account vs app users architecture
- Implementing webhook handlers
- Custom retry/rate limit strategies beyond exponential backoff
Version: 1.0 | SDK: v10+ | Last Updated: Feb 2026