# Deepgram Stt

> Deepgram Speech-to-Text (STT) - Nova-3 model with <300ms streaming latency, 36 languages, smart formatting, diarization, and endpointing. Use for real-time transcription, batch audio processing, voice AI pipelines, and call center analytics.

- Skill: `shakudo-io/deepgram-stt` (Agent Skill)
- Install (CLI): `npx skillmds@latest add shakudo-io/deepgram-stt`
- Raw SKILL.md: https://api.skillmd.com/api/skills/shakudo-io/deepgram-stt/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Data & Analytics
- License: MIT
- Author: Shakudo-io (https://skillmd.com/u/shakudo-io)
- Updated: 2026-09-22
- Page: https://skillmd.com/skills/shakudo-io/deepgram-stt

---


# Deepgram Speech-to-Text Skill

Industry-leading speech-to-text via Deepgram Nova-3. Sub-300ms streaming latency, 36 languages, smart formatting.

## Capabilities

| Feature | Endpoint | Latency | Use Case |
|---------|----------|---------|----------|
| **Streaming STT** | `wss://api.deepgram.com/v1/listen` | <300ms | Real-time conversations, Twilio, Pipecat |
| **Pre-recorded STT** | `POST /v1/listen` | Batch | Audio file transcription, call analytics |
| **Intelligence** | Built-in | N/A | Summarization, topic detection, intent recognition |

## Authentication

All requests require the `Authorization` header with a Deepgram API key:

```bash
export DEEPGRAM_API_KEY="your-api-key"
```

Header format: `Authorization: Token $DEEPGRAM_API_KEY`

## Pre-recorded Transcription

**Endpoint**: `POST https://api.deepgram.com/v1/listen`

Best for transcribing audio files, recordings, and batch processing.

### From a URL

```bash
curl -X POST "https://api.deepgram.com/v1/listen?model=nova-3&smart_format=true" \
  -H "Authorization: Token $DEEPGRAM_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"url": "https://dpgr.am/bueller.wav"}'
```

### From a Local File

```bash
curl -X POST "https://api.deepgram.com/v1/listen?model=nova-3&smart_format=true" \
  -H "Authorization: Token $DEEPGRAM_API_KEY" \
  -H "Content-Type: audio/wav" \
  --data-binary @/path/to/audio.wav
```

### With Speaker Diarization

```bash
curl -X POST "https://api.deepgram.com/v1/listen?model=nova-3&smart_format=true&diarize=true" \
  -H "Authorization: Token $DEEPGRAM_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"url": "https://dpgr.am/bueller.wav"}'
```

### With Punctuation and Paragraphs

```bash
curl -X POST "https://api.deepgram.com/v1/listen?model=nova-3&punctuate=true&paragraphs=true&utterances=true" \
  -H "Authorization: Token $DEEPGRAM_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"url": "https://dpgr.am/bueller.wav"}'
```

## Query Parameters Reference

### Model Selection

| Parameter | Value | Description |
|-----------|-------|-------------|
| `model` | `nova-3` | Latest, most accurate (recommended) |
| `model` | `nova-2` | Previous generation, still excellent |
| `model` | `nova-2-phonecall` | Optimized for telephony audio |
| `model` | `nova-2-meeting` | Optimized for meeting recordings |
| `model` | `whisper-large` | OpenAI Whisper via Deepgram |

### Formatting Options

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `smart_format` | bool | false | Auto-applies punctuate, paragraphs, numerals, dates |
| `punctuate` | bool | false | Add punctuation |
| `paragraphs` | bool | false | Split into paragraphs |
| `numerals` | bool | false | Convert spoken numbers to digits |
| `utterances` | bool | false | Segment by speaker turns |

### Intelligence Features

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `diarize` | bool | false | Identify different speakers |
| `summarize` | string | - | Set to `v2` for auto-summarization |
| `topics` | bool | false | Detect topics in audio |
| `intents` | bool | false | Detect speaker intents |
| `sentiment` | bool | false | Analyze sentiment |
| `detect_language` | bool | false | Auto-detect spoken language |

### Audio Configuration

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `language` | string | `en` | Language code (e.g., `en`, `es`, `fr`, `de`, `ja`) |
| `sample_rate` | int | auto | Audio sample rate in Hz |
| `channels` | int | auto | Number of audio channels |
| `encoding` | string | auto | Audio encoding (e.g., `linear16`, `mulaw`, `mp3`) |
| `multichannel` | bool | false | Transcribe each channel separately |

### Streaming-Specific Parameters

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `interim_results` | bool | true | Return partial results before final |
| `endpointing` | int | 10 | Silence duration (ms) to trigger endpoint (10-5000) |
| `vad_events` | bool | false | Emit voice activity detection events |
| `utterance_end_ms` | int | - | Custom utterance end timeout (ms) |

## Streaming (WebSocket) Transcription

**Endpoint**: `wss://api.deepgram.com/v1/listen`

Best for real-time applications: voice assistants, live captioning, telephony.

### Python Example (Real-time Microphone)

```python
import asyncio
import websockets
import json
import os

async def stream_microphone():
    """Stream audio to Deepgram via WebSocket for real-time transcription."""
    url = "wss://api.deepgram.com/v1/listen?model=nova-3&smart_format=true&encoding=linear16&sample_rate=16000&endpointing=300"
    
    headers = {
        "Authorization": f"Token {os.environ['DEEPGRAM_API_KEY']}"
    }
    
    async with websockets.connect(url, extra_headers=headers) as ws:
        # Send audio chunks (from microphone, file, or Twilio stream)
        # Each chunk should be raw audio bytes
        
        async def send_audio():
            # Example: send audio from a file in chunks
            with open("audio.raw", "rb") as f:
                while chunk := f.read(4096):
                    await ws.send(chunk)
                    await asyncio.sleep(0.1)  # Simulate real-time
            # Signal end of audio
            await ws.send(json.dumps({"type": "CloseStream"}))
        
        async def receive_transcripts():
            async for msg in ws:
                result = json.loads(msg)
                if result.get("type") == "Results":
                    transcript = result["channel"]["alternatives"][0]["transcript"]
                    is_final = result["is_final"]
                    if transcript:
                        prefix = "FINAL" if is_final else "INTERIM"
                        print(f"[{prefix}] {transcript}")
        
        await asyncio.gather(send_audio(), receive_transcripts())

asyncio.run(stream_microphone())
```

### Pipecat Integration Pattern

For voice AI pipelines using Pipecat with Deepgram STT:

```python
from pipecat.services.deepgram import DeepgramSTTService
from pipecat.audio.vad.silero import SileroVADAnalyzer

# Create STT service for Pipecat pipeline
stt = DeepgramSTTService(
    api_key=os.environ["DEEPGRAM_API_KEY"],
    params=DeepgramSTTService.InputParams(
        model="nova-3",
        language="en",
        smart_format=True,
        endpointing=300,       # 300ms silence = end of utterance
        utterance_end_ms=1000, # Max 1s to finalize utterance
        vad_events=True,       # Voice activity detection
        interim_results=True,  # Stream partial results
    )
)

# Use in a Pipecat pipeline:
# Twilio Audio → VAD → Deepgram STT → LLM → TTS → Twilio Audio
pipeline = Pipeline([
    transport.input(),
    SileroVADAnalyzer(),
    stt,
    llm,
    tts,
    transport.output(),
])
```

### Twilio Media Streams Integration

For receiving Twilio phone call audio and transcribing in real-time:

```python
import asyncio
import websockets
import json
import base64
import os

async def handle_twilio_stream(twilio_ws):
    """Bridge Twilio Media Stream to Deepgram for real-time transcription."""
    deepgram_url = "wss://api.deepgram.com/v1/listen?model=nova-3&encoding=mulaw&sample_rate=8000&channels=1&smart_format=true&endpointing=300"
    
    headers = {"Authorization": f"Token {os.environ['DEEPGRAM_API_KEY']}"}
    
    async with websockets.connect(deepgram_url, extra_headers=headers) as dg_ws:
        async def forward_twilio_to_deepgram():
            async for message in twilio_ws:
                data = json.loads(message)
                if data["event"] == "media":
                    # Decode Twilio's base64 mulaw audio and forward to Deepgram
                    audio = base64.b64decode(data["media"]["payload"])
                    await dg_ws.send(audio)
                elif data["event"] == "stop":
                    await dg_ws.send(json.dumps({"type": "CloseStream"}))
                    break
        
        async def receive_deepgram_results():
            async for msg in dg_ws:
                result = json.loads(msg)
                if result.get("type") == "Results":
                    transcript = result["channel"]["alternatives"][0]["transcript"]
                    if transcript and result["is_final"]:
                        print(f"Caller said: {transcript}")
                        # Send to LLM for response generation
        
        await asyncio.gather(forward_twilio_to_deepgram(), receive_deepgram_results())
```

## Response Format

### Pre-recorded Response

```json
{
  "metadata": {
    "transaction_key": "...",
    "request_id": "...",
    "sha256": "...",
    "created": "2024-01-01T00:00:00.000Z",
    "duration": 5.0,
    "channels": 1,
    "models": ["nova-3"],
    "model_info": {"nova-3": {"name": "nova-3", "version": "2025-01-01", "arch": "nova-3"}}
  },
  "results": {
    "channels": [{
      "alternatives": [{
        "transcript": "Hello, how are you today?",
        "confidence": 0.99,
        "words": [
          {"word": "hello", "start": 0.0, "end": 0.5, "confidence": 0.99, "speaker": 0},
          {"word": "how", "start": 0.6, "end": 0.8, "confidence": 0.98, "speaker": 0}
        ]
      }]
    }]
  }
}
```

### Streaming Response

```json
{
  "type": "Results",
  "channel_index": [0, 1],
  "duration": 1.5,
  "start": 0.0,
  "is_final": true,
  "speech_final": true,
  "channel": {
    "alternatives": [{
      "transcript": "Hello how are you",
      "confidence": 0.98,
      "words": [
        {"word": "hello", "start": 0.0, "end": 0.4, "confidence": 0.99}
      ]
    }]
  }
}
```

## Supported Languages (36)

| Code | Language | Code | Language |
|------|----------|------|----------|
| `en` | English | `ja` | Japanese |
| `es` | Spanish | `ko` | Korean |
| `fr` | French | `zh` | Chinese (Mandarin) |
| `de` | German | `hi` | Hindi |
| `pt` | Portuguese | `ru` | Russian |
| `it` | Italian | `nl` | Dutch |
| `sv` | Swedish | `da` | Danish |
| `no` | Norwegian | `fi` | Finnish |
| `pl` | Polish | `tr` | Turkish |
| `uk` | Ukrainian | `id` | Indonesian |
| `ta` | Tamil | `th` | Thai |
| `vi` | Vietnamese | `ms` | Malay |
| `tl` | Tagalog | `ro` | Romanian |
| `bg` | Bulgarian | `cs` | Czech |
| `el` | Greek | `hu` | Hungarian |
| `sk` | Slovak | `et` | Estonian |
| `lv` | Latvian | `lt` | Lithuanian |
| `ca` | Catalan | `gl` | Galician |

## Error Handling

| Status | Meaning | Action |
|--------|---------|--------|
| 400 | Bad request (invalid audio, missing params) | Check audio format and encoding params |
| 401 | Invalid or missing API key | Verify `Authorization: Token` header |
| 402 | Insufficient credits | Check Deepgram console for balance |
| 429 | Rate limited | Implement exponential backoff |
| 500 | Server error | Retry with backoff |

## Cost Optimization

- **Nova-3**: ~$0.0043/min (pay-as-you-go) — best accuracy-to-cost ratio
- **Nova-2**: ~$0.0036/min — slightly cheaper, still excellent
- **Streaming vs Pre-recorded**: Same price per minute
- **Multichannel**: Billed per channel, use only when needed
- **Smart format**: Free, always enable for cleaner output
- **Keywords**: Use `keywords` param to boost domain-specific terms (free)

## Quick Test

```bash
# Test pre-recorded transcription (uses Deepgram's sample audio)
curl -s -X POST "https://api.deepgram.com/v1/listen?model=nova-3&smart_format=true" \
  -H "Authorization: Token $DEEPGRAM_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"url": "https://dpgr.am/bueller.wav"}' | jq -r '.results.channels[0].alternatives[0].transcript'

# Expected output: A transcript of the Bueller movie audio clip
# If you see text output, your API key is working!

# Test with diarization (speaker identification)
curl -s -X POST "https://api.deepgram.com/v1/listen?model=nova-3&smart_format=true&diarize=true" \
  -H "Authorization: Token $DEEPGRAM_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"url": "https://dpgr.am/bueller.wav"}' | jq '.results.channels[0].alternatives[0].words[:5]'
```

