Three steps to make a document searchable:
- Create a vault (once per case)
- Upload your file
- Process it (we call this “ingest”)
After processing, the document is fully searchable by meaning.
Step 1: Create a vault
A vault is a container for your documents. Create one per case or matter.
import Casedev from 'casedev';
const client = new Casedev({ apiKey: 'sk_case_YOUR_API_KEY' });
const vault = await client.vault.create({
name: 'Smith v. Hospital 2024',
description: 'Discovery and depositions'
});
console.log(vault.id); // Save this—you'll use it for everything
{
"id": "vault_abc123xyz",
"name": "Smith v. Hospital 2024",
"description": "Discovery and depositions",
"enableIndexing": true,
"createdAt": "2025-01-15T10:30:00Z"
}
Vault options
| Option | Default | Description |
|---|
name | required | Display name for the vault |
description | optional | Description of the vault’s purpose |
enableIndexing | true | Enable vector search. Set false for storage-only vaults |
enableGraph | true | Enable GraphRAG knowledge graph (requires indexing) |
Storage-only vaults
If you only need document storage without search capabilities, create a storage-only vault:
const vault = await client.vault.create({
name: 'Archive Storage',
enableIndexing: false // No vector index, no search
});
Storage-only vaults skip vector bucket and index creation. Files can be uploaded and downloaded, but search and GraphRAG are unavailable. Use this for pure archival or when you’ll process documents externally.
Step 2: Upload a file
Uploading is two parts: get a secure URL, then PUT your file to it.
// Get an upload URL
const upload = await client.vault.upload(vault.id, {
filename: 'deposition-johnson.pdf',
contentType: 'application/pdf',
metadata: {
witness: 'Dr. Sarah Johnson',
date: '2024-11-04'
}
});
// Upload the file directly to S3
await fetch(upload.uploadUrl, {
method: 'PUT',
headers: { 'Content-Type': 'application/pdf' },
body: fileBuffer
});
console.log(upload.objectId); // Use this for the next step
Why two steps?
Security and speed. Your file goes directly to encrypted storage—we’re never a bottleneck for large uploads.
Supported file types
| Type | Extensions |
|---|
| Documents | .pdf, .doc, .docx, .txt, .rtf, .xml |
| Images | .png, .jpg, .jpeg, .tiff, .bmp |
| Audio | .mp3, .m4a, .wav, .flac, .ogg |
| Video | .mp4, .webm, .mov |
| Court recordings | .ftr |
Step 3: Process the file
This is where the magic happens. Processing (we call it “ingest”) does different things based on file type:
| File type | What we do |
|---|
| Scanned PDF, images | OCR to extract text |
| Audio, video | Transcribe with speaker labels |
| FTR recordings | Convert → Transcribe |
| Digital PDF, DOCX, TXT, RTF, XML | Extract text directly |
Then for all files: split into chunks, convert to vectors, index for search.
POST /vault/:vaultId/ingest/:objectId
const result = await client.vault.ingest(vault.id, upload.objectId);
console.log(result.status); // 'processing'
Processing time
| File | Time |
|---|
| 10-page clean PDF | ~10 seconds |
| 50-page scanned PDF | ~2-3 minutes |
| 300-page scanned PDF | ~12-15 minutes |
| 1-hour audio/video | ~5-10 minutes |
Processing is async—you get an immediate response while we work in the background.
Check status
// Poll until complete
let obj = await client.vault.objects.retrieve(vault.id, objectId);
while (obj.ingestionStatus === 'processing') {
await new Promise(r => setTimeout(r, 5000));
obj = await client.vault.objects.retrieve(vault.id, objectId);
}
if (obj.ingestionStatus === 'completed') {
console.log('Ready to search!');
}
Complete example
Upload an entire folder of discovery documents:
import Casedev from 'casedev';
import fs from 'fs';
import path from 'path';
const client = new Casedev({ apiKey: process.env.CASEDEV_API_KEY });
async function uploadDiscovery(folderPath: string) {
// 1. Create vault
const vault = await client.vault.create({
name: 'Matter 2024-1234 Discovery'
});
// 2. Upload each file
const files = fs.readdirSync(folderPath);
for (const file of files) {
const filePath = path.join(folderPath, file);
if (!fs.statSync(filePath).isFile()) continue;
// Get upload URL
const upload = await client.vault.upload(vault.id, {
filename: file,
contentType: 'application/pdf'
});
// Upload to S3
await fetch(upload.uploadUrl, {
method: 'PUT',
body: fs.readFileSync(filePath)
});
// Process
await client.vault.ingest(vault.id, upload.objectId);
console.log(`✓ ${file}`);
}
console.log(`\nVault ready: ${vault.id}`);
return vault.id;
}
uploadDiscovery('./discovery_documents');
Metadata matters. Add metadata like witness, document_type, or date when uploading—you can filter search results by these fields later.
Next: Search your documents
Now that your documents are processed, learn how to search them →