Receive and verify Deepgram webhooks (callbacks). Use when setting up Deepgram webhook handlers, processing transcription callbacks, or handling asynchronous transcription results.
85%
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
Low
Low-risk findings worth noting
Deepgram webhooks (callbacks) are used to receive transcription results asynchronously. When you provide a callback URL in your transcription request, Deepgram immediately responds with a request_id and sends the transcription results to your callback URL when processing is complete.
// Express.js example
const crypto = require('crypto');
function safeEqual(a, b) {
const ab = Buffer.from(a || '', 'utf8');
const bb = Buffer.from(b || '', 'utf8');
return ab.length === bb.length && crypto.timingSafeEqual(ab, bb);
}
app.post('/webhooks/deepgram', express.raw({ type: 'application/json' }), (req, res) => {
// 1. Primary check: Basic Auth credentials you embedded in the callback URL
// (https://user:pass@your-domain.com/webhooks/deepgram)
const auth = req.headers['authorization'] || '';
const decoded = auth.startsWith('Basic ')
? Buffer.from(auth.slice(6), 'base64').toString('utf8')
: '';
const sep = decoded.indexOf(':');
if (
sep === -1 ||
!safeEqual(decoded.slice(0, sep), process.env.DEEPGRAM_CALLBACK_USERNAME) ||
!safeEqual(decoded.slice(sep + 1), process.env.DEEPGRAM_CALLBACK_PASSWORD)
) {
return res.status(401).send('Unauthorized');
}
// 2. Supplementary check: dg-token is NOT sent on every callback,
// so only compare it when it is present
const dgToken = req.headers['dg-token'];
if (dgToken && process.env.DEEPGRAM_API_KEY_ID && !safeEqual(dgToken, process.env.DEEPGRAM_API_KEY_ID)) {
return res.status(403).send('Invalid dg-token');
}
// The callback body is the normal /v1/listen response: { metadata, results }
const payload = JSON.parse(req.body.toString());
const requestId = payload.metadata?.request_id;
const transcript = payload.results?.channels?.[0]?.alternatives?.[0]?.transcript;
console.log('Received transcription:', requestId, transcript);
// Return success to prevent retries
res.status(200).send('OK');
});Deepgram documents two ways to authenticate callbacks:
Authorization: Basic header// Basic Auth in callback URL (percent-encode special characters in the credentials)
// https://username:password@your-domain.com/webhooks/deepgram
// dg-token: check only when present
const dgToken = req.headers['dg-token'];
if (dgToken && dgToken !== process.env.DEEPGRAM_API_KEY_ID) {
return res.status(403).send('Invalid dg-token');
}curl \
--request POST \
--header 'Authorization: Token YOUR_DEEPGRAM_API_KEY' \
--header 'Content-Type: audio/wav' \
--data-binary @audio.wav \
--url 'https://api.deepgram.com/v1/listen?callback=https://username:password@your-domain.com/webhooks/deepgram'Deepgram callbacks carry no event-type field. The body is the same JSON a synchronous /v1/listen request returns: a metadata object and a results object. The structure of results varies based on the features enabled in your request:
| Field | Description | Always Present |
|---|---|---|
metadata.request_id | Unique identifier for the transcription request (matches the request_id returned when you submitted it) | Yes |
metadata.created | Timestamp when transcription was created | Yes |
metadata.duration | Length of the audio in seconds | Yes |
metadata.channels | Number of audio channels | Yes |
metadata.extra | Key-value pairs you passed with extra=KEY:VALUE | Only if extra was sent |
results.channels[].alternatives | Transcription alternatives | Yes |
results.channels[].alternatives[].transcript | The transcribed text | Yes |
results.channels[].alternatives[].confidence | Confidence score (0-1) | Yes |
# Your Deepgram API Key (for making requests)
DEEPGRAM_API_KEY=your_api_key_here
# Basic Auth credentials you embed in the callback URL (primary check)
DEEPGRAM_CALLBACK_USERNAME=your_callback_username
DEEPGRAM_CALLBACK_PASSWORD=your_callback_password
# Optional: API Key Identifier, used to check the dg-token header when present
# Note: This is NOT your API Key secret - it's a unique identifier shown
# in the Deepgram console that identifies which API key was used for a request
DEEPGRAM_API_KEY_ID=your_api_key_id_here
# Your webhook endpoint URL
WEBHOOK_URL=https://your-domain.com/webhooks/deepgramFor local webhook testing, install Hookdeck CLI:
# Create a local tunnel (no account required)
npx hookdeck-cli listen 3000 deepgram --path /webhooks/deepgram
# Use the provided URL as your callback URL when making Deepgram requestsThis provides:
dg-token header as a supplementary check because it is not sent on every callbackFor production handlers, install the patterns skill alongside this one. Key references (links work when only this skill is installed):
hookdeck/webhook-skills
694da54
If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.