> ## Documentation Index
> Fetch the complete documentation index at: https://docs.case.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Deposition Workflow

> Transcribe and analyze witness testimony with speaker labels, vault storage, and cross-examination reports

## What You'll Build

A complete deposition processing pipeline that:

1. Transcribes audio with speaker identification
2. Stores transcripts in a searchable vault
3. Generates timelines of key testimony
4. Cross-references witnesses to find contradictions
5. Produces formatted impeachment reports

**Time to complete:** 30 minutes

## Architecture

```mermaid theme={"theme":{"light":"github-light","dark":"one-dark-pro"}}
flowchart LR
    A["Audio Files<br/>(per witness)"] --> B["Voice Transcription<br/>+ Speakers"]
    B --> C["Vault Storage<br/>+ Indexing"]
    C --> D["Vault Search"]
    D --> E["LLM Analysis"]
    E --> F["PDF Report<br/>(Formatted)"]
```

## Prerequisites

* Case.dev API key ([get one here](https://console.case.dev))
* A vault for storing transcripts
* Deposition audio files (MP3, M4A, WAV, etc.)

***

## Step 1: Set Up Your Vault

Create a vault to hold all deposition transcripts for a case:

<CodeGroup>
  ```bash title="CLI" theme={"theme":{"light":"github-light","dark":"one-dark-pro"}}
  casedev vault create --name "Smith v. Jones — Depositions"
  ```

  ```typescript title="Typescript" theme={"theme":{"light":"github-light","dark":"one-dark-pro"}}
  import Casedev from 'casedev';

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

  const vault = await client.vault.create({
    name: 'Smith v. Jones — Depositions'
  });

  console.log(`Vault ID: ${vault.id}`);
  ```

  ```python title="Python" theme={"theme":{"light":"github-light","dark":"one-dark-pro"}}
  import os
  import casedev

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

  vault = client.vault.create(name='Smith v. Jones — Depositions')

  print(f'Vault ID: {vault.id}')
  ```

  ```go title="Go" theme={"theme":{"light":"github-light","dark":"one-dark-pro"}}
  vault, _ := client.Vault.New(ctx, casedev.VaultNewParams{
  	Name: casedev.F("Smith v. Jones — Depositions"),
  })
  fmt.Println(vault.ID)
  ```
</CodeGroup>

## Step 2: Upload and Transcribe a Deposition

Upload the audio file to your vault, then transcribe with speaker labels:

<CodeGroup>
  ```bash title="CLI" theme={"theme":{"light":"github-light","dark":"one-dark-pro"}}
  casedev vault upload \
    --id $VAULT_ID \
    --filename "document.pdf" \
    --content-type "application/pdf"
  ```

  ```typescript title="Typescript" theme={"theme":{"light":"github-light","dark":"one-dark-pro"}}
  async function transcribeDeposition(
    vaultId: string,
    audioFile: Buffer,
    filename: string,
    witnessName: string,
    speakersExpected: number = 3 // Witness, attorney, opposing counsel
  ) {
    // 1. Upload audio to the vault
    const upload = await client.vault.upload(vaultId, {
      filename,
      contentType: 'audio/mpeg',
      metadata: {
        witness: witnessName,
        type: 'deposition-audio'
      }
    });

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

    // 2. Transcribe with speaker labels
    const job = await client.voice.transcription.create({
      vault_id: vaultId,
      object_id: upload.objectId,
      speaker_labels: true,
      speakers_expected: speakersExpected,
      word_boost: ['plaintiff', 'defendant', 'counsel', 'objection', 'stipulate']
    });

    // 3. Poll until complete
    let result = await client.voice.transcription.retrieve(job.id);
    while (result.status !== 'completed' && result.status !== 'failed') {
      await new Promise(r => setTimeout(r, 10000));
      result = await client.voice.transcription.retrieve(job.id);
    }

    if (result.status === 'failed') {
      throw new Error(`Transcription failed: ${result.error}`);
    }

    console.log(`Transcribed ${witnessName}: ${result.word_count} words, ${Math.round(result.audio_duration / 60)} minutes`);

    return result;
  }
  ```

  ```python title="Python" theme={"theme":{"light":"github-light","dark":"one-dark-pro"}}
  import time
  import requests

  def transcribe_deposition(
      vault_id: str,
      audio_path: str,
      witness_name: str,
      speakers_expected: int = 3
  ):
      filename = os.path.basename(audio_path)

      # 1. Upload audio to the vault
      upload = client.vault.upload(vault_id,
          filename=filename,
          content_type='audio/mpeg',
          metadata={
              'witness': witness_name,
              'type': 'deposition-audio'
          }
      )

      with open(audio_path, 'rb') as f:
          requests.put(upload.upload_url, data=f,
              headers={'Content-Type': 'audio/mpeg'})

      # 2. Transcribe with speaker labels
      job = client.voice.transcription.create(
          vault_id=vault_id,
          object_id=upload.object_id,
          speaker_labels=True,
          speakers_expected=speakers_expected,
          word_boost=['plaintiff', 'defendant', 'counsel', 'objection', 'stipulate']
      )

      # 3. Poll until complete
      result = client.voice.transcription.retrieve(job.id)
      while result.status not in ('completed', 'failed'):
          time.sleep(10)
          result = client.voice.transcription.retrieve(job.id)

      if result.status == 'failed':
          raise Exception(f'Transcription failed: {result.error}')

      print(f'Transcribed {witness_name}: {result.word_count} words, {round(result.audio_duration / 60)} minutes')

      return result
  ```

  ```go title="Go" theme={"theme":{"light":"github-light","dark":"one-dark-pro"}}
  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)
  ```
</CodeGroup>

<Info>
  **Speaker labels are automatic.** The transcription service identifies speakers by voice characteristics. Set `speakers_expected` for better accuracy when you know the number of participants.
</Info>

## Step 3: Store Transcript in the Vault

The vault-based transcription automatically stores the transcript. Now ingest it for semantic search:

<CodeGroup>
  ```bash title="CLI" theme={"theme":{"light":"github-light","dark":"one-dark-pro"}}
  casedev vault ingest --id $VAULT_ID --object-id $OBJECT_ID
  ```

  ```typescript title="Typescript" theme={"theme":{"light":"github-light","dark":"one-dark-pro"}}
  async function indexTranscript(
    vaultId: string,
    resultObjectId: string,
    witnessName: string
  ) {
    // Ingest the transcript for embedding generation + search
    await client.vault.ingest(vaultId, resultObjectId);

    // Poll until indexed
    let obj = await client.vault.objects.retrieve(vaultId, resultObjectId);
    while (obj.ingestionStatus === 'processing') {
      await new Promise(r => setTimeout(r, 5000));
      obj = await client.vault.objects.retrieve(vaultId, resultObjectId);
    }

    console.log(`Indexed transcript for ${witnessName}: ${obj.ingestionStatus}`);
    return obj;
  }
  ```

  ```python title="Python" theme={"theme":{"light":"github-light","dark":"one-dark-pro"}}
  def index_transcript(vault_id: str, result_object_id: str, witness_name: str):
      # Ingest the transcript for embedding generation + search
      client.vault.ingest(result_object_id, id=vault_id)

      # Poll until indexed
      obj = client.vault.objects.retrieve(vault_id, result_object_id)
      while obj.ingestion_status == 'processing':
          time.sleep(5)
          obj = client.vault.objects.retrieve(vault_id, result_object_id)

      print(f'Indexed transcript for {witness_name}: {obj.ingestion_status}')
      return obj
  ```

  ```go title="Go" theme={"theme":{"light":"github-light","dark":"one-dark-pro"}}
  result, _ := client.Vault.Ingest(ctx, vaultID, objectID)
  fmt.Println(result.Status)
  ```
</CodeGroup>

<Tip>
  For production, use [webhooks](/vault/webhooks) instead of polling for both transcription and ingestion status changes.
</Tip>

## Step 4: Batch Process Multiple Depositions

Process all depositions for a case in sequence:

<CodeGroup>
  ```bash title="CLI" theme={"theme":{"light":"github-light","dark":"one-dark-pro"}}
  # Process depositions sequentially
  for AUDIO in depositions/*.mp3; do
    WITNESS=$(basename "$AUDIO" .mp3)
    echo "Processing: $WITNESS"

    # Transcribe
    casedev voice:transcription create \
      --vault-id $VAULT_ID --file "$AUDIO" \
      --speaker-labels --language en-US

    # Index transcript is automatic when vault indexing is enabled
  done
  ```

  ```typescript title="Typescript" theme={"theme":{"light":"github-light","dark":"one-dark-pro"}}
  interface Deposition {
    audioFile: Buffer;
    filename: string;
    witnessName: string;
    date: string;
  }

  async function processCase(vaultId: string, depositions: Deposition[]) {
    const results = [];

    for (const depo of depositions) {
      console.log(`\nProcessing: ${depo.witnessName} (${depo.date})`);

      // Transcribe
      const transcription = await transcribeDeposition(
        vaultId,
        depo.audioFile,
        depo.filename,
        depo.witnessName
      );

      // Index for search
      await indexTranscript(vaultId, transcription.result_object_id, depo.witnessName);

      results.push({
        witness: depo.witnessName,
        date: depo.date,
        objectId: transcription.result_object_id,
        wordCount: transcription.word_count,
        duration: transcription.audio_duration
      });
    }

    console.log(`\nProcessed ${results.length} depositions`);
    return results;
  }
  ```

  ```python title="Python" theme={"theme":{"light":"github-light","dark":"one-dark-pro"}}
  def process_case(vault_id: str, depositions: list[dict]):
      results = []

      for depo in depositions:
          print(f"\nProcessing: {depo['witness_name']} ({depo['date']})")

          # Transcribe
          transcription = transcribe_deposition(
              vault_id,
              depo['audio_path'],
              depo['witness_name']
          )

          # Index for search
          index_transcript(vault_id, transcription.result_object_id, depo['witness_name'])

          results.append({
              'witness': depo['witness_name'],
              'date': depo['date'],
              'object_id': transcription.result_object_id,
              'word_count': transcription.word_count,
              'duration': transcription.audio_duration
          })

      print(f'\nProcessed {len(results)} depositions')
      return results
  ```

  ```go title="Go" theme={"theme":{"light":"github-light","dark":"one-dark-pro"}}
  func processCase(ctx context.Context, client *casedev.Client, vaultID string, depositions []Deposition) []Result {
  	var results []Result
  	for _, depo := range depositions {
  		fmt.Printf("\nProcessing: %s (%s)\n", depo.WitnessName, depo.Date)
  		transcription := transcribeDeposition(ctx, client, vaultID, depo)
  		indexTranscript(ctx, client, vaultID, transcription.ResultObjectID, depo.WitnessName)
  		results = append(results, Result{
  			Witness:  depo.WitnessName,
  			ObjectID: transcription.ResultObjectID,
  		})
  	}
  	fmt.Printf("\nProcessed %d depositions\n", len(results))
  	return results
  }
  ```
</CodeGroup>

## Step 5: Generate a Testimony Timeline

Search across all depositions and build a chronological timeline of events:

<CodeGroup>
  ```bash title="CLI" theme={"theme":{"light":"github-light","dark":"one-dark-pro"}}
  # Search vault for testimony, then pipe to LLM
  casedev vault search --id $VAULT_ID \
    --query "timeline of events" --method hybrid --limit 15

  casedev llm:v1:chat create-completion \
    --model anthropic/claude-sonnet-4.5 \
    --message '{role: system, content: "Extract a chronological timeline from deposition testimony."}' \
    --message '{role: user, content: "<testimony excerpts from search>"}' \
    --temperature 0.2
  ```

  ```typescript title="Typescript" theme={"theme":{"light":"github-light","dark":"one-dark-pro"}}
  async function generateTimeline(vaultId: string, topic: string) {
    // Search across all indexed transcripts
    const results = await client.vault.search(vaultId, {
      query: `timeline of events regarding ${topic}`,
      method: 'hybrid',
      limit: 20
    });

    const chunks = results.chunks.map(c => c.text).join('\n\n');
    const sources = results.sources.map(s => s.filename).join(', ');

    // Generate structured timeline
    const timeline = await client.llm.v1.chat.createCompletion({
      model: 'anthropic/claude-sonnet-4.5',
      messages: [
        {
          role: 'system',
          content: `You are a litigation paralegal. Create a chronological timeline from deposition testimony.

  For each event:
  - Date (exact or approximate)
  - What happened
  - Who testified about it (witness name)
  - Direct quote from testimony
  - Page/line reference if available

  Format as a markdown table sorted by date.`
        },
        {
          role: 'user',
          content: `Topic: ${topic}\n\nTestimony excerpts:\n${chunks}\n\nSources: ${sources}`
        }
      ],
      temperature: 0.2
    });

    return timeline.choices[0].message.content;
  }
  ```

  ```python title="Python" theme={"theme":{"light":"github-light","dark":"one-dark-pro"}}
  def generate_timeline(vault_id: str, topic: str):
      # Search across all indexed transcripts
      results = client.vault.search(vault_id,
          query=f'timeline of events regarding {topic}',
          method='hybrid',
          top_k=20
      )

      chunks = '\n\n'.join(c.text for c in results.chunks)
      sources = ', '.join(s.filename for s in results.sources)

      # Generate structured timeline
      timeline = client.llm.v1.chat.create_completion(
          model='anthropic/claude-sonnet-4.5',
          messages=[
              {
                  'role': 'system',
                  'content': '''You are a litigation paralegal. Create a chronological timeline from deposition testimony.

  For each event:
  - Date (exact or approximate)
  - What happened
  - Who testified about it (witness name)
  - Direct quote from testimony
  - Page/line reference if available

  Format as a markdown table sorted by date.'''
              },
              {
                  'role': 'user',
                  'content': f'Topic: {topic}\n\nTestimony excerpts:\n{chunks}\n\nSources: {sources}'
              }
          ],
          temperature=0.2
      )

      return timeline.choices[0].message.content
  ```

  ```go title="Go" theme={"theme":{"light":"github-light","dark":"one-dark-pro"}}
  // Search vault for testimony on a topic
  results, _ := client.Vault.Search(ctx, vaultID, casedev.VaultSearchParams{
  	Query:  casedev.F(topic),
  	Method: casedev.F(casedev.VaultSearchParamsMethodHybrid),
  	TopK:   casedev.F(int64(15)),
  })

  // Build context from search results
  var chunks string
  for _, c := range results.Chunks {
  	chunks += c.Text + "\n\n"
  }

  // Generate timeline via LLM
  timeline, _ := 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("You are a litigation paralegal. Extract a chronological timeline from deposition testimony."),
  		},
  		{
  			Role:    casedev.F(casedev.LlmV1ChatNewCompletionParamsMessagesRoleUser),
  			Content: casedev.F("Topic: " + topic + "\n\nTestimony excerpts:\n" + chunks),
  		},
  	}),
  	Temperature: casedev.F(float64(0.2)),
  })
  fmt.Println(timeline.Choices[0].Message.Content)
  ```
</CodeGroup>

## Step 6: Find Contradictions Across Witnesses

Search for a topic and compare what different witnesses said:

<CodeGroup>
  ```bash title="CLI" theme={"theme":{"light":"github-light","dark":"one-dark-pro"}}
  # Search for testimony across witnesses
  casedev vault search --id $VAULT_ID \
    --query "accident description" --method hybrid --limit 20

  # Analyze contradictions
  casedev llm:v1:chat create-completion \
    --model anthropic/claude-sonnet-4.5 \
    --message '{role: system, content: "Identify contradictions and inconsistencies across witness testimony."}' \
    --message '{role: user, content: "<grouped testimony from search>"}' \
    --temperature 0.3
  ```

  ```typescript title="Typescript" theme={"theme":{"light":"github-light","dark":"one-dark-pro"}}
  async function findContradictions(vaultId: string, topic: string) {
    // Search across all testimony for the topic
    const results = await client.vault.search(vaultId, {
      query: topic,
      method: 'hybrid',
      limit: 20
    });

    // Group by source file (each transcript = one witness)
    const byWitness: Record<string, string[]> = {};
    for (const chunk of results.chunks) {
      const witness = chunk.metadata?.witness || chunk.filename;
      if (!byWitness[witness]) byWitness[witness] = [];
      byWitness[witness].push(chunk.text);
    }

    // Use AI to find contradictions
    const analysis = await client.llm.v1.chat.createCompletion({
      model: 'anthropic/claude-sonnet-4.5',
      messages: [
        {
          role: 'system',
          content: `You are a litigation attorney preparing for cross-examination.
          
  Analyze testimony from multiple witnesses and identify:
  1. Direct contradictions (conflicting facts)
  2. Inconsistencies (different emphasis or omissions)
  3. Corroborations (matching testimony across witnesses)

  For each finding, cite the specific quote and witness name.
  Rate each contradiction as HIGH, MEDIUM, or LOW significance.`
        },
        {
          role: 'user',
          content: `Topic: ${topic}\n\nTestimony by witness:\n${
            Object.entries(byWitness)
              .map(([w, texts]) => `\n## ${w}\n${texts.join('\n')}`)
              .join('\n')
          }`
        }
      ],
      temperature: 0.3
    });

    return analysis.choices[0].message.content;
  }
  ```

  ```python title="Python" theme={"theme":{"light":"github-light","dark":"one-dark-pro"}}
  def find_contradictions(vault_id: str, topic: str):
      # Search across all testimony for the topic
      results = client.vault.search(vault_id,
          query=topic,
          method='hybrid',
          top_k=20
      )

      # Group by source file (each transcript = one witness)
      by_witness = {}
      for chunk in results.chunks:
          witness = chunk.metadata.get('witness', chunk.filename)
          if witness not in by_witness:
              by_witness[witness] = []
          by_witness[witness].append(chunk.text)

      # Use AI to find contradictions
      testimony_text = '\n'.join([
          f'\n## {w}\n{chr(10).join(texts)}'
          for w, texts in by_witness.items()
      ])

      analysis = client.llm.v1.chat.create_completion(
          model='anthropic/claude-sonnet-4.5',
          messages=[
              {
                  'role': 'system',
                  'content': '''You are a litigation attorney preparing for cross-examination.

  Analyze testimony from multiple witnesses and identify:
  1. Direct contradictions (conflicting facts)
  2. Inconsistencies (different emphasis or omissions)
  3. Corroborations (matching testimony across witnesses)

  For each finding, cite the specific quote and witness name.
  Rate each contradiction as HIGH, MEDIUM, or LOW significance.'''
              },
              {
                  'role': 'user',
                  'content': f'Topic: {topic}\n\nTestimony by witness:\n{testimony_text}'
              }
          ],
          temperature=0.3
      )

      return analysis.choices[0].message.content
  ```

  ```go title="Go" theme={"theme":{"light":"github-light","dark":"one-dark-pro"}}
  // Search across all testimony for the topic
  results, _ := client.Vault.Search(ctx, vaultID, casedev.VaultSearchParams{
  	Query:  casedev.F(topic),
  	Method: casedev.F(casedev.VaultSearchParamsMethodHybrid),
  	TopK:   casedev.F(int64(20)),
  })

  // Group testimony by witness and build context
  var testimonyText string
  for _, chunk := range results.Chunks {
  	testimonyText += fmt.Sprintf("## %s\n%s\n\n", chunk.Filename, chunk.Text)
  }

  // Analyze contradictions via LLM
  analysis, _ := 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("You are a litigation attorney. Identify contradictions, inconsistencies, and corroborations across witness testimony."),
  		},
  		{
  			Role:    casedev.F(casedev.LlmV1ChatNewCompletionParamsMessagesRoleUser),
  			Content: casedev.F("Topic: " + topic + "\n\nTestimony by witness:\n" + testimonyText),
  		},
  	}),
  	Temperature: casedev.F(float64(0.3)),
  })
  fmt.Println(analysis.Choices[0].Message.Content)
  ```
</CodeGroup>

## Step 7: Generate a PDF Impeachment Report

Combine the timeline and contradiction analysis into a formatted report:

<CodeGroup>
  ```bash title="CLI" theme={"theme":{"light":"github-light","dark":"one-dark-pro"}}
  casedev format:v1 document \
    --content "# Report" \
    --input-format md --output-format pdf
  ```

  ```typescript title="Typescript" theme={"theme":{"light":"github-light","dark":"one-dark-pro"}}
  async function generateImpeachmentReport(
    vaultId: string,
    caseName: string,
    topics: string[]
  ) {
    let reportContent = `# Impeachment Report\n\n**Case:** ${caseName}\n**Generated:** ${new Date().toLocaleDateString()}\n\n---\n\n`;

    // Generate timeline
    reportContent += `## Chronological Timeline\n\n`;
    const timeline = await generateTimeline(vaultId, caseName);
    reportContent += timeline + '\n\n---\n\n';

    // Analyze each topic
    reportContent += `## Contradiction Analysis\n\n`;
    for (const topic of topics) {
      reportContent += `### ${topic}\n\n`;
      const contradictions = await findContradictions(vaultId, topic);
      reportContent += contradictions + '\n\n';
    }

    // Convert to PDF
    const report = await client.format.v1.document({
      content: reportContent,
      input_format: 'md',
      output_format: 'pdf',
      options: {
        template: 'standard',
        header: `CONFIDENTIAL — ${caseName} — Impeachment Report`,
        footer: 'Page {{page}} of {{pages}}',
        styles: {
          h1: { font: 'Times New Roman', size: 16, bold: true, alignment: 'center' },
          h2: { font: 'Times New Roman', size: 14, bold: true },
          h3: { font: 'Times New Roman', size: 12, bold: true },
          p: { font: 'Times New Roman', size: 11, spacingAfter: 8 }
        }
      }
    });

    return report;
  }
  ```

  ```python title="Python" theme={"theme":{"light":"github-light","dark":"one-dark-pro"}}
  from datetime import date

  def generate_impeachment_report(vault_id: str, case_name: str, topics: list[str]):
      report_content = f'# Impeachment Report\n\n**Case:** {case_name}\n**Generated:** {date.today().isoformat()}\n\n---\n\n'

      # Generate timeline
      report_content += '## Chronological Timeline\n\n'
      timeline = generate_timeline(vault_id, case_name)
      report_content += timeline + '\n\n---\n\n'

      # Analyze each topic
      report_content += '## Contradiction Analysis\n\n'
      for topic in topics:
          report_content += f'### {topic}\n\n'
          contradictions = find_contradictions(vault_id, topic)
          report_content += contradictions + '\n\n'

      # Convert to PDF
      report = client.format.v1.create_document(
          content=report_content,
          input_format='md',
          output_format='pdf',
          options={
              'template': 'standard',
              'header': f'CONFIDENTIAL — {case_name} — Impeachment Report',
              'footer': 'Page {{page}} of {{pages}}',
              'styles': {
                  'h1': {'font': 'Times New Roman', 'size': 16, 'bold': True, 'alignment': 'center'},
                  'h2': {'font': 'Times New Roman', 'size': 14, 'bold': True},
                  'h3': {'font': 'Times New Roman', 'size': 12, 'bold': True},
                  'p': {'font': 'Times New Roman', 'size': 11, 'spacingAfter': 8}
              }
          }
      )

      return report
  ```

  ```go title="Go" theme={"theme":{"light":"github-light","dark":"one-dark-pro"}}
  result, _ := client.Format.V1.NewDocument(ctx, casedev.FormatV1NewDocumentParams{
  	Content:      casedev.F("# Report\n\nContent here..."),
  	InputFormat:  casedev.F("md"),
  	OutputFormat: casedev.F("pdf"),
  })
  // result is *http.Response with PDF body
  ```
</CodeGroup>

***

## Complete Example

Putting it all together:

<CodeGroup>
  ```bash title="CLI" theme={"theme":{"light":"github-light","dark":"one-dark-pro"}}
  casedev vault create --name "Smith v. Jones — Depositions"
  ```

  ```typescript title="Typescript" theme={"theme":{"light":"github-light","dark":"one-dark-pro"}}
  import Casedev from 'casedev';
  import fs from 'fs';

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

  async function main() {
    // Create a vault for the case
    const vault = await client.vault.create({
      name: 'Smith v. Jones — Depositions'
    });

    // Process depositions
    await processCase(vault.id, [
      {
        audioFile: fs.readFileSync('depositions/ceo-johnson.m4a'),
        filename: 'ceo-johnson.m4a',
        witnessName: 'CEO Johnson',
        date: '2024-03-15'
      },
      {
        audioFile: fs.readFileSync('depositions/cto-smith.m4a'),
        filename: 'cto-smith.m4a',
        witnessName: 'CTO Smith',
        date: '2024-03-18'
      },
      {
        audioFile: fs.readFileSync('depositions/it-director-williams.m4a'),
        filename: 'it-director-williams.m4a',
        witnessName: 'IT Director Williams',
        date: '2024-03-20'
      }
    ]);

    // Generate impeachment report
    const report = await generateImpeachmentReport(
      vault.id,
      'Smith v. Jones',
      [
        'When the CEO learned of the data breach',
        'Who authorized the system shutdown',
        'Timeline of security notifications'
      ]
    );

    console.log('Report generated successfully');
  }

  main();
  ```

  ```python title="Python" theme={"theme":{"light":"github-light","dark":"one-dark-pro"}}
  import os
  import casedev

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

  def main():
      # Create a vault for the case
      vault = client.vault.create(name='Smith v. Jones — Depositions')

      # Process depositions
      process_case(vault.id, [
          {
              'audio_path': 'depositions/ceo-johnson.m4a',
              'witness_name': 'CEO Johnson',
              'date': '2024-03-15'
          },
          {
              'audio_path': 'depositions/cto-smith.m4a',
              'witness_name': 'CTO Smith',
              'date': '2024-03-18'
          },
          {
              'audio_path': 'depositions/it-director-williams.m4a',
              'witness_name': 'IT Director Williams',
              'date': '2024-03-20'
          }
      ])

      # Generate impeachment report
      report = generate_impeachment_report(
          vault.id,
          'Smith v. Jones',
          [
              'When the CEO learned of the data breach',
              'Who authorized the system shutdown',
              'Timeline of security notifications'
          ]
      )

      print('Report generated successfully')

  main()
  ```

  ```go title="Go" theme={"theme":{"light":"github-light","dark":"one-dark-pro"}}
  vault, _ := client.Vault.New(ctx, casedev.VaultNewParams{
  	Name: casedev.F("Smith v. Jones — Depositions"),
  })
  fmt.Println(vault.ID)
  ```
</CodeGroup>

## Example Contradiction Report

```markdown theme={"theme":{"light":"github-light","dark":"one-dark-pro"}}

### Topic: When the CEO learned of the data breach

**CEO Johnson (Deposition, March 15, 2024):**
> "I was not informed of any security incident until July 15th,
> when our IT director called me at home."

**CTO Smith (Deposition, March 18, 2024):**
> "I sent an urgent email to the entire executive team, including
> the CEO, on July 12th explicitly detailing the intrusion and
> recommending immediate action."

**IT Director Williams (Deposition, March 20, 2024):**
> "The CTO instructed me to brief the CEO on July 12th. I called
> his office but was told he was unavailable. I left a detailed
> voicemail."

### Analysis
The CEO claims no knowledge until July 15th, but both the CTO and
IT Director indicate notification attempts on July 12th — three days
earlier. The CTO claims direct email notification, and the IT
Director confirms a voicemail was left.

### Impeachment Strategy
1. Introduce July 12th email as Exhibit A
2. Subpoena CEO's voicemail records for July 12th
3. Confront CEO with CTO and IT Director testimony
```

***

## Production Tips

### Error Handling

<CodeGroup>
  ```bash title="CLI" theme={"theme":{"light":"github-light","dark":"one-dark-pro"}}
  # CLI displays errors to stderr with status codes
  casedev voice:transcription create --vault-id $VAULT_ID --object-id $AUDIO_OBJECT_ID
  # Error: 413 Payload Too Large — split into segments
  # Error: 429 Too Many Requests — retry after a delay
  ```

  ```typescript title="Typescript" theme={"theme":{"light":"github-light","dark":"one-dark-pro"}}
  try {
    const result = await transcribeDeposition(vaultId, audio, filename, witness);
  } catch (error) {
    if (error.status === 413) {
      console.error('Audio file too large — split into segments');
    } else if (error.status === 429) {
      console.error('Rate limited — retry after a delay');
    } else {
      console.error('Transcription failed:', error.message);
    }
  }
  ```

  ```python title="Python" theme={"theme":{"light":"github-light","dark":"one-dark-pro"}}
  try:
      result = transcribe_deposition(vault_id, audio_path, witness)
  except casedev.APIError:
      print('Audio file too large — split into segments')
  except casedev.RateLimitError:
      print('Rate limited — retry after a delay')
  except casedev.APIError as e:
      print(f'Transcription failed: {e.message}')
  ```

  ```go title="Go" theme={"theme":{"light":"github-light","dark":"one-dark-pro"}}
  result, err := transcribeDeposition(ctx, client, vaultID, audio, filename, witness)
  if err != nil {
  	var apiErr *casedev.Error
  	if errors.As(err, &apiErr) {
  		switch apiErr.StatusCode {
  		case 413:
  			fmt.Println("Audio file too large — split into segments")
  		case 429:
  			fmt.Println("Rate limited — retry after a delay")
  		default:
  			fmt.Printf("Transcription failed: %s\n", apiErr.Message)
  		}
  	}
  }
  ```
</CodeGroup>

### Use Webhooks in Production

Instead of polling, subscribe to events for transcription and ingestion completion:

<CodeGroup>
  ```bash title="CLI" theme={"theme":{"light":"github-light","dark":"one-dark-pro"}}
  # Subscribe to vault events
  casedev vault:events:subscriptions create \
    --id $VAULT_ID \
    --callback-url "https://your-app.com/webhooks/vault" \
    --event-type object.ingested \
    --event-type object.failed

  # Subscribe to transcription events
  # Your webhook handler receives status updates automatically
  ```

  ```typescript title="Typescript" theme={"theme":{"light":"github-light","dark":"one-dark-pro"}}
  // Subscribe to vault events
  await client.vault.events.subscriptions.create(vaultId, {
    url: 'https://your-app.com/webhooks/vault',
    events: ['object.ingested', 'object.failed']
  });

  // Subscribe to transcription events
  // Your webhook handler receives status updates automatically
  ```

  ```python title="Python" theme={"theme":{"light":"github-light","dark":"one-dark-pro"}}
  # Subscribe to vault events
  client.vault.events.subscriptions.create(vault_id,
      callback_url='https://your-app.com/webhooks/vault',
      event_types=['object.ingested', 'object.failed']
  )

  # Subscribe to transcription events
  # Your webhook handler receives status updates automatically
  ```

  ```go title="Go" theme={"theme":{"light":"github-light","dark":"one-dark-pro"}}
  // Subscribe to vault events
  client.Vault.Events.Subscriptions.New(ctx, vaultID, casedev.VaultEventSubscriptionNewParams{
      CallbackURL: casedev.F("https://your-app.com/webhooks/vault"),
      EventTypes:  casedev.F([]string{"object.ingested", "object.failed"}),
  })

  // Subscribe to transcription events
  // Your webhook handler receives status updates automatically
  ```
</CodeGroup>

<Tip>
  For long depositions (2+ hours), transcription may take several minutes. Webhooks prevent wasted polling requests.
</Tip>

***

## Next Steps

* [Voice Transcription Reference](/voice/transcription) — Speaker labels, language options, and more
* [Vault Search Reference](/vault/search) — Advanced search methods and filtering
* [Format Service](/format/index) — PDF and DOCX generation
* [Discovery Pipeline](/cookbooks/discovery-pipeline) — Batch document processing
