Documents
The Documents resource provides full CRUD operations for managing documents in Sonar.
List Documents
Retrieves a paginated list of documents with optional filters.
Endpoint: GET /api/sdk/v1/documents
Parameters (ListDocumentsParams)
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
page | number | No | 1 | Page number (minimum: 1) |
limit | number | No | 20 | Items per page (minimum: 1, maximum: 100) |
classification | DocumentClassification | No | — | Filter by: 'generated', 'uploaded', or 'signed' |
isSigned | boolean | No | — | Filter by signature status |
type | string | No | — | Filter by MIME type (e.g., 'application/pdf') |
uploadFrom | DocumentUploadSource | No | — | Filter by upload source |
sessionId | string | No | — | Filter by session ID (MongoDB ObjectId) |
fromDate | string | Date | No | — | Filter documents from this date (ISO 8601) |
toDate | string | Date | No | — | Filter documents up to this date (ISO 8601) |
Response (ListDocumentsResponse)
| Field | Type | Description |
|---|---|---|
docs | Document[] | Array of document objects |
totalDocs | number | Total number of matching documents |
limit | number | Items per page |
totalPages | number | Total number of pages |
page | number | Current page number |
pagingCounter | number | Serial number of the first document on this page |
hasPrevPage | boolean | Whether a previous page exists |
hasNextPage | boolean | Whether a next page exists |
prevPage | number | null | Previous page number or null |
nextPage | number | null | Next page number or null |
Example
// Basic listingconst response = await sdk.documents.list();console.log(response.docs); // Document[]console.log(response.totalDocs); // total count
// With filtersconst signedPDFs = await sdk.documents.list({ page: 1, limit: 50, classification: 'signed', isSigned: true, type: 'application/pdf', fromDate: '2025-01-01T00:00:00Z', toDate: new Date(),});
// Pagination looplet page = 1;let hasMore = true;while (hasMore) { const result = await sdk.documents.list({ page, limit: 100 }); console.log(`Page ${page}: ${result.docs.length} documents`); hasMore = result.hasNextPage; page++;}Get a Document
Retrieves a single document by its ID.
Endpoint: GET /api/sdk/v1/documents/:id
| Parameter | Type | Required | Description |
|---|---|---|---|
documentId | string | Yes | The document identifier |
Returns: Document object
Throws: DocumentNotFoundError if the document does not exist.
try { const doc = await sdk.documents.get('doc_abc123'); console.log(doc.name); // "contract.pdf" console.log(doc.isSigned); // true console.log(doc.extension); // "pdf" console.log(doc.size); // "245632"} catch (err) { if (err instanceof DocumentNotFoundError) { console.log(`Document ${err.documentId} not found`); }}Download a Document
Downloads the binary file content of a document.
Endpoint: GET /api/sdk/v1/documents/:id/download
| Parameter | Type | Required | Description |
|---|---|---|---|
documentId | string | Yes | The document identifier |
Response (DownloadResponse)
| Field | Type | Description |
|---|---|---|
data | ArrayBuffer | The raw file data |
contentType | string | MIME type (e.g., 'application/pdf') |
filename | string | Original filename from server |
size | number | Size in bytes |
import { writeFileSync } from 'fs';
const { data, filename, contentType, size } = await sdk.documents.download('doc_abc123');
// Save to diskwriteFileSync(`./${filename}`, Buffer.from(data));console.log(`Downloaded ${filename} (${size} bytes, ${contentType})`);Upload a Document
Uploads a new document to Sonar. The SDK handles multipart/form-data encoding automatically.
Endpoint: POST /api/sdk/v1/documents/upload
Parameters (UploadDocumentParams)
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
file | Buffer | Blob | NodeJS.ReadableStream | Yes | — | The file data to upload |
filename | string | No | — | Original filename |
contentType | string | No | application/octet-stream | MIME type of the file |
name | string | No | — | Display name for the document |
uploadFrom | DocumentUploadSource | No | 'user-documents' | Source/context of the upload |
identity | string | No | — | Identity string for the uploader |
classification | DocumentClassification | No | 'uploaded' | Document classification category |
Upload Source Values (DocumentUploadSource)
| Value | Description |
|---|---|
'session-chat' | Uploaded during a chat session |
'session-call' | Uploaded during a call session |
'user-documents' | Uploaded from user document management |
'session-recording' | From a session recording |
'queue-documents' | From a queue/processing pipeline |
'application-settings-appearance' | Application settings upload |
File Input Types
The SDK supports three input types for the file parameter:
Buffer(Node.js) — Converted toBlobwith the providedcontentTypeBlob(Browser/Node.js 18+) — Used directlyReadableStream(Node.js) — Chunks are collected, concatenated, and wrapped as aBlob
Returns: Document object (the newly created document)
import { readFileSync, createReadStream } from 'fs';
// Upload from Bufferconst buffer = readFileSync('./contract.pdf');const doc = await sdk.documents.upload({ file: buffer, filename: 'contract.pdf', contentType: 'application/pdf', name: 'Q1 Contract', uploadFrom: 'user-documents', classification: 'uploaded',});console.log(`Uploaded: ${doc.id} — ${doc.name}`);
// Upload from ReadableStreamconst stream = createReadStream('./report.xlsx');const doc2 = await sdk.documents.upload({ file: stream, filename: 'report.xlsx', contentType: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', classification: 'generated',});
// Upload from Blob (browser environment)const blob = new Blob([arrayBuffer], { type: 'application/pdf' });const doc3 = await sdk.documents.upload({ file: blob, filename: 'scan.pdf',});Delete a Document
Permanently deletes a document by its ID. This action cannot be undone.
Endpoint: DELETE /api/sdk/v1/documents/:id
| Parameter | Type | Required | Description |
|---|---|---|---|
documentId | string | Yes | The document identifier |
Returns: DeleteDocumentResponse with { documentId: string }
Throws: ValidationError if documentId is empty. DocumentNotFoundError if the document does not exist.
Required Scope: documents:{classification}:delete
// Delete a single documentconst { documentId } = await sdk.documents.delete('doc_abc123');console.log(`Deleted: ${documentId}`);
// With error handlingtry { await sdk.documents.delete('doc_abc123');} catch (err) { if (err instanceof DocumentNotFoundError) { console.log(`Document ${err.documentId} not found`); }}Batch Delete Documents
Deletes multiple documents in a single request.
Endpoint: POST /api/sdk/v1/documents/delete
Parameters (BatchDeleteParams)
| Parameter | Type | Required | Description |
|---|---|---|---|
documentIds | string[] | Yes | Array of document IDs to delete (min: 1, max: 500) |
Client-Side Validation:
- Throws
ValidationErrorifdocumentIdsis empty - Throws
ValidationErrorifdocumentIdshas more than 500 items
Response (BatchDeleteResponse)
| Field | Type | Description |
|---|---|---|
deleted | number | Number of documents successfully deleted |
failed | number | Number of documents that failed to delete |
total | number | Total number of documents in the request |
const result = await sdk.documents.batchDelete({ documentIds: ['doc_001', 'doc_002', 'doc_003'],});console.log(`Deleted ${result.deleted} of ${result.total}`);
if (result.failed > 0) { console.warn(`${result.failed} documents failed to delete`);}Get Presigned Download URL
Generates a temporary presigned URL for downloading a document.
Endpoint: GET /api/sdk/v1/documents/:id/download-url
| Parameter | Type | Required | Description |
|---|---|---|---|
documentId | string | Yes | The document identifier |
Query Parameters (DownloadUrlParams)
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
expiresIn | number | No | 300 | URL expiry in seconds (min: 60, max: 3600) |
Response (DownloadUrlResponse)
| Field | Type | Description |
|---|---|---|
documentId | string | The document identifier |
name | string | Document name |
url | string | Presigned download URL |
expiresIn | number | URL expiry time in seconds |
// Get a download URL with default expiry (300s)const { url, expiresIn } = await sdk.documents.getDownloadUrl('doc_abc123');console.log(`Download at: ${url} (expires in ${expiresIn}s)`);
// Get a URL with custom expiry (10 minutes)const { url: longUrl } = await sdk.documents.getDownloadUrl('doc_abc123', { expiresIn: 600,});
// Redirect a client to the download URL (Express)app.get('/download/:id', async (req, res) => { const { url } = await sdk.documents.getDownloadUrl(req.params.id, { expiresIn: 120, }); res.redirect(url);});Export Documents as ZIP
Exports multiple documents bundled into a single ZIP archive.
Endpoint: POST /api/sdk/v1/documents/export
Parameters (ExportDocumentsParams)
| Parameter | Type | Required | Description |
|---|---|---|---|
documentIds | string[] | Yes | Array of document IDs to export (min: 1, max: 500) |
Client-Side Validation:
- Throws
ValidationErrorifdocumentIdsis empty - Throws
ValidationErrorifdocumentIdshas more than 500 items
Returns: DownloadResponse with data (ArrayBuffer), contentType ('application/zip'), filename, and size.
import { writeFileSync } from 'fs';
const { data, filename, size } = await sdk.documents.export({ documentIds: ['doc_001', 'doc_002', 'doc_003'],});
writeFileSync(`./${filename}`, Buffer.from(data));console.log(`Exported ${filename} (${size} bytes)`);