Skip to main content
The problem: You have 50 hours of video depositions. You suspect the CEO contradicted the CTO on the breach timeline, but you can’t re-watch everything. The solution: Transcribe the audio, search by topic, and use AI to find contradictions.

1. Transcribe the depositions

curl -X POST https://api.case.dev/voice/transcription \
  -H "Authorization: Bearer $CASEDEV_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "audio_url": "https://your-storage.com/user-recording.mp4",
    "speaker_labels": true,
    "auto_chapters": true
  }'
casedev voice:transcription create \
  --audio-url "https://storage.example.com/recording.mp3" \
  --speaker-labels
import Casedev from 'casedev';

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

// Transcribe audio uploaded by your user
const job = await client.voice.transcription.create({
  audio_url: audioUrl, // URL from your user's upload
  speaker_labels: true,  // Identify who's speaking
  auto_chapters: true    // Detect topic changes
});

console.log(`Transcription started: ${job.id}`);
import casedev
import os

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

# Transcribe audio uploaded by your user
job = client.voice.transcription.create(
    audio_url=audio_url,  # URL from your user's upload
    speaker_labels=True,  # Identify who's speaking
    auto_chapters=True    # Detect topic changes
)

print(f'Transcription started: {job.id}')
job, _ := client.Voice.Transcription.New(ctx, casedev.VoiceTranscriptionNewParams{
	AudioURL:      casedev.F("https://storage.example.com/recording.mp3"),
	SpeakerLabels: casedev.F(true),
})
fmt.Println(job.ID)

2. Get the transcripts

# Get transcription result
curl "https://api.case.dev/voice/transcription/$JOB_ID" \
  -H "Authorization: Bearer $CASEDEV_API_KEY"
casedev voice:transcription create \
  --audio-url "https://storage.example.com/recording.mp3" \
  --speaker-labels
// Wait for completion
async function waitForTranscription(jobId: string) {
  let result = await client.voice.transcription.retrieve(jobId);

  while (result.status !== 'completed') {
    if (result.status === 'error') throw new Error('Transcription failed');
    await new Promise(r => setTimeout(r, 10000));
    result = await client.voice.transcription.retrieve(jobId);
  }

  return result;
}

const transcript = await waitForTranscription(job.id);

// Deliver speaker-labeled transcript to your user
for (const utterance of transcript.utterances) {
  console.log(`${utterance.speaker}: ${utterance.text}`);
}
import time

def wait_for_transcription(job_id: str):
    result = client.voice.transcription.retrieve(job_id)

    while result.status != 'completed':
        if result.status == 'error':
            raise Exception('Transcription failed')
        time.sleep(10)
        result = client.voice.transcription.retrieve(job_id)

    return result

transcript = wait_for_transcription(job.id)

# Deliver speaker-labeled transcript to your user
for utterance in transcript.utterances:
    print(f'{utterance.speaker}: {utterance.text}')
job, _ := client.Voice.Transcription.New(ctx, casedev.VoiceTranscriptionNewParams{
	AudioURL:      casedev.F("https://storage.example.com/recording.mp3"),
	SpeakerLabels: casedev.F(true),
})
fmt.Println(job.ID)
Store transcripts in a vault so your users can search across multiple recordings:
# Create vault
VAULT=$(curl -s -X POST https://api.case.dev/vault \
  -H "Authorization: Bearer $CASEDEV_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name": "Audio Transcripts - User 12345"}')

VAULT_ID=$(echo $VAULT | jq -r '.id')
casedev vault create --name "Audio Transcripts - User 12345"
// Create a vault for your user's transcripts
const vault = await client.vault.create({
  name: 'Audio Transcripts - User 12345'
});

// Upload transcript as a searchable document
async function uploadTranscript(vaultId: string, name: string, text: string) {
  const upload = await client.vault.upload(vaultId, {
    filename: `${name}.txt`,
    contentType: 'text/plain'
  });

  await fetch(upload.uploadUrl, {
    method: 'PUT',
    headers: { 'Content-Type': 'text/plain' },
    body: text
  });

  await client.vault.ingest(vaultId, upload.objectId);
}

await uploadTranscript(vault.id, 'recording-001', transcript.text);
import requests

# Create a vault for your user's transcripts
vault = client.vault.create(name='Audio Transcripts - User 12345')

def upload_transcript(vault_id: str, name: str, text: str):
    upload = client.vault.upload(vault_id,
        filename=f'{name}.txt',
        content_type='text/plain'
    )

    requests.put(upload.upload_url, data=text.encode(),
        headers={'Content-Type': 'text/plain'})

    client.vault.ingest(upload.object_id, id=vault_id)

upload_transcript(vault.id, 'recording-001', transcript.text)
vault, _ := client.Vault.New(ctx, casedev.VaultNewParams{
	Name: casedev.F("Audio Transcripts - User 12345"),
})
fmt.Println(vault.ID)

4. Find contradictions

Help your users extract insights from transcripts:
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 this transcript. Identify key points and action items."},
      {"role": "user", "content": "[TRANSCRIPT TEXT]"}
    ]
  }'
casedev llm:v1:chat create-completion \
  --model anthropic/claude-sonnet-4.5 \
  --message '{role: system, content: "Summarize this transcript. Identify key points, action items, and any notable quotes."}' \
  --message '{role: user, content: "<transcript text>"}'
// Analyze transcript for your user
const analysis = await client.llm.v1.chat.createCompletion({
  model: 'anthropic/claude-sonnet-4.5',
  messages: [
    {
      role: 'system',
      content: 'Summarize this transcript. Identify key points, action items, and any notable quotes.'
    },
    {
      role: 'user',
      content: transcript.text
    }
  ]
});

// Return analysis to your user
console.log(analysis.choices[0].message.content);
# Analyze transcript for your user
analysis = client.llm.v1.chat.create_completion(
    model='anthropic/claude-sonnet-4.5',
    messages=[
        {
            'role': 'system',
            'content': 'Summarize this transcript. Identify key points, action items, and any notable quotes.'
        },
        {
            'role': 'user',
            'content': transcript.text
        }
    ]
)

# Return analysis to your user
print(analysis.choices[0].message.content)
// Analyze transcript 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 this transcript. Identify key points, action items, and any notable quotes."),
		},
		{
			Role:    casedev.F(casedev.LlmV1ChatNewCompletionParamsMessagesRoleUser),
			Content: casedev.F(transcript.Text),
		},
	}),
})

// Return analysis to your user
fmt.Println(resp.Choices[0].Message.Content)
Example output: Build advanced features like contradiction detection for legal applications:
# Search for statements about a specific topic
casedev vault search \
  --id $VAULT_ID \
  --query "timeline of events on July 15th" \
  --top-k 10

# Use AI to identify contradictions (pipe search results)
casedev llm:v1:chat create-completion \
  --model anthropic/claude-sonnet-4.6 \
  --message '{"role":"system","content":"Analyze these statements and identify any contradictions. Cite specific quotes."}' \
  --message '{"role":"user","content":"<search results>"}'
// Search for statements about a specific topic
const statements = await client.vault.search(vault.id, {
  query: 'timeline of events on July 15th',
  topK: 10
});

// Use AI to identify contradictions
const contradictions = await client.llm.v1.chat.createCompletion({
  model: 'anthropic/claude-sonnet-4.5',
  messages: [
    {
      role: 'system',
      content: 'Analyze these statements and identify any contradictions. Cite specific quotes.'
    },
    {
      role: 'user',
      content: statements.chunks.map(c => c.text).join('\n\n')
    }
  ]
});

console.log(contradictions.choices[0].message.content);
# Search for statements about a specific topic
statements = client.vault.search(vault.id,
    query='timeline of events on July 15th',
    top_k=10
)

# Use AI to identify contradictions
contradictions = client.llm.v1.chat.create_completion(
    model='anthropic/claude-sonnet-4.5',
    messages=[
        {
            'role': 'system',
            'content': 'Analyze these statements and identify any contradictions. Cite specific quotes.'
        },
        {
            'role': 'user',
            'content': '\n\n'.join(c.text for c in statements.chunks)
        }
    ]
)

print(contradictions.choices[0].message.content)
// Search for statements about a specific topic
statements, _ := client.Vault.Search(ctx, vaultID, casedev.VaultSearchParams{
    Query: casedev.F("timeline of events on July 15th"),
    TopK:  casedev.F(int64(10)),
})

// Build content from chunks
var texts []string
for _, chunk := range statements.Chunks {
    texts = append(texts, chunk.Text)
}
content := strings.Join(texts, "\n\n")

// Use AI to identify contradictions
contradictions, _ := 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("Analyze these statements and identify any contradictions. Cite specific quotes."),
        },
        {
            Role:    casedev.F(casedev.LlmV1ChatNewCompletionParamsMessagesRoleUser),
            Content: casedev.F(content),
        },
    }),
})

fmt.Println(contradictions.Choices[0].Message.Content)
Time saved: What used to take days of re-watching video now takes minutes. The AI finds contradictions you might have missed.