Skip to main content 首页 创作者 comeonoliver skillshub deepgram-webhooks-events
deepgram-webhooks-events Implement Deepgram callback and webhook handling for async transcription.
Use when implementing callback URLs, processing async transcription results,
or handling Deepgram event notifications.
Trigger: "deepgram callback", "deepgram webhook", "async transcription",
"deepgram events", "deepgram notifications", "deepgram async".
跳到安装 Skills Marketplace 发现并探索由社区构建的 Agent Skills
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
直接命令不会经过审查 Prompt;运行前请先检查来源。
npx skills add https://github.com/ComeOnOliver/skillshub --skill deepgram-webhooks-events命令会保持在同一行。复制前请横向滚动并检查完整内容。
想先保存到本地?可下载 SkillsMP 当前能够提供的文件。
下载 Zip 下载中... name deepgram-webhooks-events description Implement Deepgram callback and webhook handling for async transcription.
Use when implementing callback URLs, processing async transcription results,
or handling Deepgram event notifications.
Trigger: "deepgram callback", "deepgram webhook", "async transcription",
"deepgram events", "deepgram notifications", "deepgram async".
allowed-tools Read, Write, Edit, Bash(curl:*) version 1.0.0 license MIT author Jeremy Longshore <jeremy@intentsolutions.io> compatible-with claude-code, codex, openclaw tags ["saas","deepgram","webhooks","transcription","async"]
Deepgram Webhooks & Callbacks
Overview
Implement async transcription with Deepgram's callback feature. When you pass a callback URL, Deepgram returns a request_id immediately, processes audio in the background, and POSTs results to your endpoint. Supports HTTP and WebSocket callbacks with automatic retry (10 attempts, 30s intervals).
Deepgram Callback Flow
1. Client -> POST /v1/listen?callback=https://you.com/webhook (with audio)
2. Deepgram -> 200 { request_id: "..." } (immediate)
3. Deepgram processes audio asynchronously
4. Deepgram -> POST https://you.com/webhook (results)
Retries up to 10 times (30s delay) on non-2xx response
Instructions
Step 1: Submit Async Transcription
import { createClient } from '@deepgram/sdk' ;
const deepgram = createClient (process.env .DEEPGRAM_API_KEY !);
async function submitAsync (audioUrl : string , callbackUrl : string ) {
const { result, error } = await deepgram.listen .prerecorded .transcribeUrl (
{ url : audioUrl },
{
model : 'nova-3' ,
smart_format : true ,
diarize : true ,
utterances : true ,
callback : callbackUrl,
}
);
(error) ( );
requestId = result. . ;
. ( );
. ( );
requestId;
}
if
throw
new
Error
`Submit failed: ${error.message} `
const
metadata
request_id
console
log
`Submitted. Request ID: ${requestId} `
console
log
`Results will be POSTed to: ${callbackUrl} `
return
Step 2: Callback Server import express from 'express' ;
import crypto from 'crypto' ;
const app = express ();
app.use ('/webhooks/deepgram' , express.raw ({ type : 'application/json' , limit : '50mb' }));
app.post ('/webhooks/deepgram' , async (req, res) => {
try {
const signature = req.headers ['x-deepgram-signature' ] as string ;
if (process.env .DEEPGRAM_WEBHOOK_SECRET && signature) {
const expected = crypto
.createHmac ('sha256' , process.env .DEEPGRAM_WEBHOOK_SECRET )
.update (req.body )
.digest ('hex' );
if (!crypto.timingSafeEqual (Buffer .from (signature), Buffer .from (expected))) {
console .error ('Invalid webhook signature' );
return res.status (401 ).json ({ error : 'Invalid signature' });
}
}
const result = JSON .parse (req.body .toString ());
const requestId = result.metadata ?.request_id ;
const transcript = result.results ?.channels ?.[0 ]?.alternatives ?.[0 ]?.transcript ;
const duration = result.metadata ?.duration ;
console .log (`Callback received: ${requestId} ` );
console .log (`Duration: ${duration} s` );
console .log (`Transcript: ${transcript?.substring(0 , 200 )} ...` );
await processTranscriptionResult (requestId, result);
res.status (200 ).json ({ received : true , request_id : requestId });
} catch (err : any ) {
console .error ('Callback processing error:' , err.message );
res.status (500 ).json ({ error : 'Processing failed' });
}
});
async function processTranscriptionResult (requestId : string , result : any ) {
const transcript = result.results .channels [0 ].alternatives [0 ];
const record = {
requestId,
transcript : transcript.transcript ,
confidence : transcript.confidence ,
duration : result.metadata .duration ,
words : transcript.words ?.length ?? 0 ,
utterances : result.results .utterances ?.map ((u : any ) => ({
speaker : u.speaker ,
text : u.transcript ,
start : u.start ,
end : u.end ,
})),
processedAt : new Date ().toISOString (),
};
console .log ('Processed:' , JSON .stringify (record, null , 2 ));
return record;
}
Step 3: Job Tracking with Redis import Redis from 'ioredis' ;
const redis = new Redis (process.env .REDIS_URL ?? 'redis://localhost:6379' );
class TranscriptionJobTracker {
async submit (requestId : string , metadata : Record <string , any > ) {
await redis.hset (`job:${requestId} ` , {
status : 'processing' ,
submittedAt : new Date ().toISOString (),
...metadata,
});
await redis.expire (`job:${requestId} ` , 86400 );
}
async complete (requestId : string , result : any ) {
await redis.hset (`job:${requestId} ` , {
status : 'completed' ,
completedAt : new Date ().toISOString (),
transcript : result.results .channels [0 ].alternatives [0 ].transcript ,
duration : result.metadata .duration ,
});
await redis.publish ('transcription:complete' , JSON .stringify ({
requestId,
duration : result.metadata .duration ,
}));
}
async getStatus (requestId : string ) {
return redis.hgetall (`job:${requestId} ` );
}
}
app.get ('/api/transcription/:requestId' , async (req, res) => {
const tracker = new TranscriptionJobTracker ();
const status = await tracker.getStatus (req.params .requestId );
if (!status || Object .keys (status).length === 0 ) {
return res.status (404 ).json ({ error : 'Job not found' });
}
res.json (status);
});
Step 4: Client SDK with Submit/Poll/Wait class AsyncTranscriptionClient {
private deepgram : ReturnType <typeof createClient>;
private baseUrl : string ;
constructor (apiKey : string , serverBaseUrl : string ) {
this .deepgram = createClient (apiKey);
this .baseUrl = serverBaseUrl;
}
async submit (audioUrl : string ): Promise <string > {
const callbackUrl = `${this .baseUrl} /webhooks/deepgram` ;
const { result, error } = await this .deepgram .listen .prerecorded .transcribeUrl (
{ url : audioUrl },
{ model : 'nova-3' , smart_format : true , diarize : true , callback : callbackUrl }
);
if (error) throw error;
return result.metadata .request_id ;
}
async poll (requestId : string ): Promise <any > {
const res = await fetch (`${this .baseUrl} /api/transcription/${requestId} ` );
if (res.status === 404 ) return null ;
return res.json ();
}
async waitForResult (requestId : string , timeoutMs = 300000 ): Promise <any > {
const start = Date .now ();
while (Date .now () - start < timeoutMs) {
const status = await this .poll (requestId);
if (status?.status === 'completed' ) return status;
if (status?.status === 'failed' ) throw new Error ('Transcription failed' );
await new Promise (r => setTimeout (r, 2000 ));
}
throw new Error ('Timeout waiting for transcription' );
}
}
const client = new AsyncTranscriptionClient (
process.env .DEEPGRAM_API_KEY !,
'https://your-server.com'
);
const requestId = await client.submit ('https://example.com/long-recording.wav' );
const result = await client.waitForResult (requestId);
Step 5: Local Testing with ngrok
ngrok http 3000
curl -X POST 'https://api.deepgram.com/v1/listen?model=nova-3&callback=https://abc123.ngrok.io/webhooks/deepgram' \
-H "Authorization: Token $DEEPGRAM_API_KEY " \
-H "Content-Type: application/json" \
-d '{"url":"https://static.deepgram.com/examples/nasa-podcast.wav"}'
Step 6: Idempotent Processing
const processedRequests = new Set <string >();
app.post ('/webhooks/deepgram' , async (req, res) => {
const result = JSON .parse (req.body .toString ());
const requestId = result.metadata ?.request_id ;
if (processedRequests.has (requestId)) {
console .log (`Duplicate callback for ${requestId} — skipping` );
return res.status (200 ).json ({ received : true , duplicate : true });
}
processedRequests.add (requestId);
await processTranscriptionResult (requestId, result);
res.status (200 ).json ({ received : true });
});
Output
Async transcription submission with callback URL
Callback server with signature verification
Redis-backed job tracking with pub/sub notifications
Client SDK with submit/poll/wait pattern
Idempotent callback processing
Local testing setup with ngrok
Error Handling Issue Cause Solution Callback not received Endpoint unreachable Check HTTPS, firewall, use ngrok for local Duplicate callbacks Deepgram retry after slow response Implement idempotency with request_id Invalid signature Wrong webhook secret Verify DEEPGRAM_WEBHOOK_SECRET matches Console Processing timeout Slow downstream Return 200 immediately, process async Large payload Long audio transcript Increase express.raw limit
Resources