Skip to main content
The problem: You have 5,000 documents from discovery. Finding the relevant ones takes weeks of manual review. The solution: Upload to a Vault. We OCR, chunk, and index everything. Search by meaning in seconds.

1. Create a vault

Vaults are secure containers for your users’ documents. Each vault gets automatic OCR, chunking, and vector indexing.
curl -X POST https://api.case.dev/vault \
  -H "Authorization: Bearer $CASEDEV_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Case Documents - User 12345",
    "description": "Discovery documents for case review"
  }'
casedev vault create --name "Case Documents - User 12345"
import Casedev from 'casedev';

const client = new Casedev({ apiKey: process.env.CASEDEV_API_KEY });

// Create a vault for your user's documents
const vault = await client.vault.create({
  name: 'Case Documents - User 12345',
  description: 'Discovery documents for case review'
});

console.log(`Vault created: ${vault.id}`);
import casedev
import os

client = casedev.Casedev(api_key=os.environ['CASEDEV_API_KEY'])

# Create a vault for your user's documents
vault = client.vault.create(
    name='Case Documents - User 12345',
    description='Discovery documents for case review'
)

print(f'Vault created: {vault.id}')
vault, _ := client.Vault.New(ctx, casedev.VaultNewParams{
	Name: casedev.F("Case Documents - User 12345"),
	Description: casedev.F("Discovery documents for case review"),
})
fmt.Println(vault.ID)

2. Upload documents

Handle file uploads from your users and trigger automatic processing:
# 1. Get upload URL
UPLOAD=$(curl -s -X POST "https://api.case.dev/vault/$VAULT_ID/upload" \
  -H "Authorization: Bearer $CASEDEV_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"filename": "document.pdf", "contentType": "application/pdf"}')

UPLOAD_URL=$(echo $UPLOAD | jq -r '.uploadUrl')
OBJECT_ID=$(echo $UPLOAD | jq -r '.objectId')

# 2. Upload file
curl -X PUT "$UPLOAD_URL" \
  -H "Content-Type: application/pdf" \
  --data-binary "@document.pdf"

# 3. Trigger ingestion
curl -X POST "https://api.case.dev/vault/$VAULT_ID/ingest/$OBJECT_ID" \
  -H "Authorization: Bearer $CASEDEV_API_KEY"
casedev vault upload \
  --id $VAULT_ID \
  --filename "document.pdf" \
  --content-type "application/pdf"
import fs from 'fs';

async function uploadDocument(vaultId: string, filePath: string) {
  // Get presigned upload URL
  const upload = await client.vault.upload(vaultId, {
    filename: filePath.split('/').pop()!,
    contentType: 'application/pdf'
  });

  // Upload file to S3
  const file = fs.readFileSync(filePath);
  await fetch(upload.uploadUrl, {
    method: 'PUT',
    headers: { 'Content-Type': 'application/pdf' },
    body: file
  });

  // Trigger OCR + embedding pipeline
  await client.vault.ingest(vaultId, upload.objectId);

  return upload.objectId;
}

// Process uploads from your user
const files = fs.readdirSync('./uploads');
for (const file of files) {
  await uploadDocument(vault.id, `./uploads/${file}`);
  console.log(`Processed: ${file}`);
}
import os
import requests

def upload_document(vault_id: str, file_path: str) -> str:
    # Get presigned upload URL
    upload = client.vault.upload(vault_id,
        filename=os.path.basename(file_path),
        content_type='application/pdf'
    )

    # Upload file to S3
    with open(file_path, 'rb') as f:
        requests.put(upload.upload_url, data=f,
            headers={'Content-Type': 'application/pdf'})

    # Trigger OCR + embedding pipeline
    client.vault.ingest(upload.object_id, id=vault_id)

    return upload.object_id

# Process uploads from your user
for file in os.listdir('./uploads'):
    upload_document(vault.id, f'./uploads/{file}')
    print(f'Processed: {file}')
upload, _ := client.Vault.Upload(ctx, vaultID, casedev.VaultUploadParams{
	Filename:    casedev.F("document.pdf"),
	ContentType: casedev.F("application/pdf"),
})
// PUT file to upload.UploadURL via net/http
fmt.Println(upload.ObjectID)

3. Search by meaning

Enable your users to search by meaning, not just keywords:
curl -X POST "https://api.case.dev/vault/$VAULT_ID/search" \
  -H "Authorization: Bearer $CASEDEV_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "query": "communications about equipment failure",
    "method": "hybrid",
    "topK": 10
  }'
casedev vault search \
  --id $VAULT_ID \
  --query "search query"
// In your search endpoint or UI handler
const results = await client.vault.search(vault.id, {
  query: userQuery, // e.g., "communications about equipment failure"
  method: 'hybrid',
  topK: 10
});

// Return results to your user
for (const chunk of results.chunks) {
  console.log(`📄 ${chunk.filename} (score: ${chunk.hybridScore.toFixed(2)})`);
  console.log(`"${chunk.text.substring(0, 200)}..."`);
}
# In your search endpoint or UI handler
results = client.vault.search(vault.id,
    query=user_query,  # e.g., "communications about equipment failure"
    method='hybrid',
    top_k=10
)

# Return results to your user
for chunk in results.chunks:
    print(f'📄 {chunk.filename} (score: {chunk.hybrid_score:.2f})')
    print(f'"{chunk.text[:200]}..."')
results, _ := client.Vault.Search(ctx, vaultID, casedev.VaultSearchParams{
	Query: casedev.F("search query"),
	Method: casedev.F(casedev.VaultSearchParamsMethodHybrid),
})
for _, chunk := range results.Chunks {
	fmt.Println(chunk.Text)
}

4. Summarize findings

Enhance results with AI-generated summaries for your users:
curl -X POST https://api.case.dev/llm/v1/chat/completions \
  -H "Authorization: Bearer $CASEDEV_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "anthropic/claude-sonnet-4.5",
    "messages": [
      {"role": "system", "content": "Summarize these search results concisely."},
      {"role": "user", "content": "User searched for: [QUERY]\n\nResults:\n\n[SEARCH RESULTS]"}
    ],
    "max_tokens": 500
  }'
casedev llm:v1:chat create-completion \
  --model anthropic/claude-sonnet-4.5 \
  --message '{role: system, content: "Summarize these search results concisely. Highlight the most relevant findings."}' \
  --message '{role: user, content: "User searched for: <query>\n\nResults:\n\n<search results>"}' \
  --max-tokens 500
const context = results.chunks.map(c => c.text).join('\n\n---\n\n');

const summary = await client.llm.v1.chat.createCompletion({
  model: 'anthropic/claude-sonnet-4.5',
  messages: [
    {
      role: 'system',
      content: 'Summarize these search results concisely. Highlight the most relevant findings.'
    },
    {
      role: 'user',
      content: `User searched for: "${userQuery}"\n\nResults:\n\n${context}`
    }
  ],
  max_tokens: 500
});

// Return summary along with search results
console.log(summary.choices[0].message.content);
context = '\n\n---\n\n'.join([c.text for c in results.chunks])

summary = client.llm.v1.chat.create_completion(
    model='anthropic/claude-sonnet-4.5',
    messages=[
        {
            'role': 'system',
            'content': 'Summarize these search results concisely. Highlight the most relevant findings.'
        },
        {
            'role': 'user',
            'content': f'User searched for: "{user_query}"\n\nResults:\n\n{context}'
        }
    ],
    max_tokens=500
)

# Return summary along with search results
print(summary.choices[0].message.content)
// Summarize search results for your user
resp, _ := client.Llm.V1.Chat.NewCompletion(ctx, casedev.LlmV1ChatNewCompletionParams{
	Model: casedev.F("anthropic/claude-sonnet-4.5"),
	Messages: casedev.F([]casedev.LlmV1ChatNewCompletionParamsMessage{
		{
			Role:    casedev.F(casedev.LlmV1ChatNewCompletionParamsMessagesRoleSystem),
			Content: casedev.F("Summarize these search results concisely. Highlight the most relevant findings."),
		},
		{
			Role:    casedev.F(casedev.LlmV1ChatNewCompletionParamsMessagesRoleUser),
			Content: casedev.F("User searched for: " + query + "\n\nResults:\n\n" + searchResultsText),
		},
	}),
	MaxTokens: casedev.F(int64(500)),
})
fmt.Println(resp.Choices[0].Message.Content)
Time saved: What used to take weeks of manual review now takes minutes. The AI finds relevant passages even when documents use different terminology.